如何获取元素的className、Id 和nth:child(n) 以便成为一个好的稳定的querySelector?

How to get element's className, Id, and nth:child(n) in order to be a good stable querySelector?

我正在通过 X、Y 坐标获取元素。我希望我的最终字符串结果看起来像 Inspect -> copySelector:

body > div.layout.slidein-page-container > main > div.ng-scope > section.wrapper.wrapper--canvas > div > div > div > div:nth-child(2)

所以从中计算 JSHandle 将是很好的 queryString。

这是我的代码:

let chosenElement = await page.evaluate((payload) => {
        return document.elementsFromPoint(payload.data.x, payload.data.y)
            .map((o) => {
                if (o.id) {
                    return o.id;
                } else if (o.className) {
                    if (o.className.includes(' ')) {
                        return o.tagName.toLowerCase() + '.' + o.className.split(' ').join('.');
                    } else {
                        return o.tagName.toLowerCase() + '.' + o.className;
                    }
                } else {
                    return o.tagName.toLowerCase();
                }
            }).reverse().join(' > ');
    }, payload);

所以目前我只检查 className 和 Id,但我想让它更精确。

我首先需要帮助的是如何检查元素是否为第 nth-child(2) 示例?

你能帮我一个更好的解决方案吗

您可以将元素的 parent children 从 HTMLCollection 转换为数组:

Array.from(o.parentElement.children)

找到你的元素的索引:

const oIndex = Array.from(o.parentElement.children).indexOf(o);

return 选择器:

return `${o.tagName}:nth-child(${oIndex + 1})`;

你需要加 1 因为 nth-child 从 1 开始,数组中的索引从 0 开始;

顺便说一句:

  • 您在构建选择器时忘记在 id 前添加 #
  • 您不需要将选择器中的标记名小写
  • 如果 object 有一个类名,你可以简单地 return ${o.tagName}.${Array.from(o.classList).join('.')}

我希望这对其他人有所帮助

  let chosenElement = await page.evaluate((payload) => {
        return document.elementsFromPoint(payload.data.x, payload.data.y)
            .map((o) => {
                let sibArr = Array.from(o.parentNode.children).filter(i => i.tagName === o.tagName);
                if (sibArr.indexOf(o) > 0) {
                    let oIndex = sibArr.indexOf(o);
                    return `${o.tagName.toLowerCase()}:nth-child(${oIndex + 1})`;
                } else if (o.id) {
                    return '#' + o.id;
                } else if (o.className) {
                    return `${o.tagName.toLowerCase()}.${Array.from(o.classList).join('.')}`
                } else {
                    return o.tagName.toLowerCase();
                }
            }).reverse().filter(e => !e.includes('html')).join(' > ');
    }, payload);

这符合预期的结果:

body > div:nth-child(3) > header.layout__header.slidein-page > div.container > nav.nav-bar > ul.nav-bar__nav > li:nth-child(3) > a