如何使用Puppeteer和纯JavaScript检查元素是否可见?

akn*_*ds1 8 javascript css puppeteer

我希望检查一下使用Puppeteer和纯JavaScript(不是jQuery)可以看到DOM元素,我该怎么做?通过可见我的意思是元素通过CSS显示,而不是隐藏(f.ex.by display: none).

例如,我可以#menu通过display: none以下方式确定我的元素是否未通过CSS规则隐藏:

const isNotHidden = await page.$eval('#menu', (elem) => {
  return elem.style.display !== 'none'
})
Run Code Online (Sandbox Code Playgroud)

如何确定元素是否隐藏,而不仅仅是通过display: none

akn*_*ds1 22

我发现Puppeteer有一个用于此目的的API方法:Page.waitForSelector,通过它的visible选项.我不知道后一个选项,但它让你等到一个元素可见.

await page.waitForSelector('#element', {
  visible: true,
})
Run Code Online (Sandbox Code Playgroud)

相反,您可以通过hidden选项等待隐藏元素.

对于Puppeteer API,我认为这是惯用的答案.感谢Colin Cline,因为我认为他的答案可能是一般的JavaScript解决方案.

  • 如果元素不可见,这将抛出。如果元素不可见是完全可以接受的,那么抛出是不合适的。我希望开发人员停止为正常行为抛出异常,只返回一个像 null 这样的值! (2认同)
  • @Gerry,这正是我的问题,我想检查该元素,然后在该元素尚未准备好时根据该元素执行某些操作,但在查找该元素时它会抛出并使应用程序崩溃 (2认同)
  • 问题是如何测试一个元素是否可见,而不是等待它被添加到 DOM 然后变得可见,这就是这个“已接受”解决方案的作用。 (2认同)
  • 我不明白如果元素不存在(由于等待),可接受的答案是如何使脚本暂停的答案 (2认同)

huy*_*ham 8

使用 boundingBox()

此方法返回元素的边界框(相对于主框架),如果元素不可见,则返回 null。

API:https : //github.com/puppeteer/puppeteer/blob/master/docs/api.md#elementhandleboundingbox


Col*_*ine 6

一种是通过检查其显示样式值。 是通过检查它的高度,为EXP如果元素是它是一个元素的子元素display: none中,offsetHeight将是0这样的话你知道该元素是不是尽管它的显示值可见。opacity: 0不被视为隐藏元素,因此我们将不对其进行检查。

const isNotHidden = await page.$eval('#menu', (elem) => {
    return window.getComputedStyle(elem).getPropertyValue('display') !== 'none' && elem.offsetHeight
});
Run Code Online (Sandbox Code Playgroud)

elem.offsetWidth在进行任何计算之前,您也可以检查并可以检查元素是否存在。


Gra*_*ler 5

当前接受的答案涉及等待元素出现变得可见。

如果我们不是在等待的元素感兴趣,我们只是想测试元素的可见性,我们可以使用的组合getComputedStyle(),并getBoundingClientRect()以测试元素是否可见。

我们可以先检查visibility未设置为hidden

然后我们就可以验证该边界框是通过检查可见bottomtopheight,和width属性未设置0(这将过滤掉那些元素display设置none为好)。

const element_is_visible = await page.evaluate(() => {
  const element = document.querySelector('#example');
  const style = getComputedStyle(element);
  const rect = element.getBoundingClientRect();

  return style.visibility !== 'hidden' && !!(rect.bottom || rect.top || rect.height || rect.width);
});
Run Code Online (Sandbox Code Playgroud)

  • 这不适用于其他元素后面的元素(即:z-index 中的堆叠元素)...是否有像这样的全功能解决方案? (2认同)

Thi*_* NV 5

也许你可以使用elementHandle.boundingBox()(感谢@huypham idea)

它将返回一个 Promise,显示元素的边界框(相对于主框架),如果元素不可见,则返回 null。

片段示例:

      const loadMoreButton = await getDataPage.$(
        'button.ao-tour-reviews__load-more-cta.js-ao-tour-reviews__load-more-cta'
      );

      const buttonVisible = await loadMoreButton.boundingBox();

      if (buttonVisible) {
        await loadMoreButton.click().catch((e) => {
          console.log(': ' + e)
        });
      }
Run Code Online (Sandbox Code Playgroud)