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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/47712679/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 07:33:37  来源:igfitidea点击:

How can I check that an element is visible with Puppeteer and pure JavaScript?

javascriptcssnode.jspuppeteervisibility

提问by aknuds1

I wish to check that a DOM element is visible with Puppeteerand pure JavaScript (not jQuery), how can I do this? By visible I mean that the element is displayed through CSS, and not hidden (f.ex. by display: none).

我想用Puppeteer和纯 JavaScript(不是 jQuery)检查 DOM 元素是否可见,我该怎么做?可见我的意思是元素通过 CSS 显示,而不是隐藏(例如 by display: none)。

For example, I can determine whether my element #menuis not hidden via CSS rule display: none, in the following way:

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

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

How can I determine in general though if the element is hidden or not, and not just through display: none?

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

回答by aknuds1

I found that Puppeteer has an API method for this purpose: Page.waitForSelector, via its visibleoption. I wasn't aware of the latter option, but it lets you wait until an element is visible.

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

await page.waitForSelector('#element', {
  visible: true,
})

Conversely you can wait for an element to be hidden, via the hiddenoption.

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

I think this is the idiomatic answer, with regards to the Puppeteer API. Thanks to Colin Cline though as I think his answer is probably useful as a general JavaScript solution.

我认为这是关于 Puppeteer API 的惯用答案。感谢 Colin Cline,因为我认为他的回答作为通用 JavaScript 解决方案可能很有用。

回答by Colin Cline

Oneis by checking its display style value. Secondis by checking its height, for exp if the element is a child of an element which is display: none, the offsetHeightwill be 0and thus you know the element is not visible despite its display value. opacity: 0is not considered as hidden element so we will not checking it.

一种是通过检查其显示样式值。 其次是通过检查它的高度,对于 exp,如果元素是元素的子元素display: noneoffsetHeight则将是0,因此您知道该元素不可见,尽管其显示值。opacity: 0不被视为隐藏元素,因此我们不会检查它。

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

You can check elem.offsetWidthas well and is not bad before any calculation, check if element exist or not.

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

回答by huypham

Use boundingBox()

使用 boundingBox()

This method returns the bounding box of the element (relative to the main frame), or null if the element is not visible.

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

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

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

回答by ashish

this code definitely help you. It basically means the element is already available on the page but is not visible yet or in CSS, the display property is set as none or visibility is hidden. Now, while writing our tests, we assume that as soon as the element is available, do an action on it like clicking or typing. But as this element is not yet visible, Puppeteer fails to perform that action.

这段代码绝对可以帮助你。这基本上意味着该元素已经在页面上可用但尚不可见,或者在 CSS 中,显示属性设置为无或可见性被隐藏。现在,在编写我们的测试时,我们假设只要元素可用,就对其执行操作,例如单击或键入。但由于此元素尚不可见,Puppeteer 无法执行该操作。

async function isLocatorReady(element, page) {
  const isVisibleHandle = await page.evaluateHandle((e) => 
{
    const style = window.getComputedStyle(e);
    return (style && style.display !== 'none' && 
    style.visibility !== 'hidden' && style.opacity !== '0');
 }, element);
  var visible = await isVisibleHandle.jsonValue();
  const box = await element.boxModel();
  if (visible && box) {
    return true;
  }
  return false;
}

回答by pguardiario

Apparently here's how jQuery does it:

显然,jQuery 是这样做的:

visible = await page.evaluate((e) => e.offsetWidth > 0 && e.offsetHeight > 0, element)

回答by Wade

If you just want to know if an element is visible or not then you can use this function. You should make sure that the page is ready before calling this function. You can do that by using waitForSelector on other elements you expect to be visible.

如果你只是想知道一个元素是否可见,那么你可以使用这个函数。在调用此函数之前,您应该确保页面已准备就绪。您可以通过在您希望可见的其他元素上使用 waitForSelector 来做到这一点。

async function isVisible(page, selector) {
  return await page.evaluate((selector) => {
    var e = document.querySelector(selector);
    if (e) {
      var style = window.getComputedStyle(e);

      return style && style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0';
    }
    else {
      return false;
    }
  }, selector);
}


// Example usage:
page.waitForSelector('#otherPeerElement');
var myElementIsVisible = await isVisible(page, '#visibleOrNot');

if (myElementIsVisible) {
// Interact with #visibleOrNot
}

回答by Grant Miller

The current accepted answer involves waitingfor an element to appear andbecome visible.

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

If we are not interested in waiting on the element, and we would simply like to test the visibility of the element, we can use a combination of getComputedStyle()and getBoundingClientRect()to test whether or not the element is visible.

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

We can first check that the visibilityis not set to hidden.

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

Then we can validate that the bounding box is visible by checking that the bottom, top, height, and widthattributes are not set to 0(this will filter out elements that have displayset to noneas well).

然后我们就可以验证该边界框是通过检查可见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);
});

回答by Antuan

I would use @aknuds1 's approach, but you can also do the following.

我会使用 @aknuds1 的方法,但您也可以执行以下操作。

expect((await page.$('#element')) !== null).toEqual(true)

If you are fetching a resource asynchronously, be aware that the above expectation may not pass, since it won't wait for the changes to reflect on the UI. That's why this approach may not be preferred in this scenario.

如果您异步获取资源,请注意上述期望可能不会通过,因为它不会等待更改反映在 UI 上。这就是为什么在这种情况下可能不首选这种方法的原因。