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

时间:2017-12-08 10:43:28

标签: javascript css puppeteer

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

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

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

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

11 个答案:

答案 0 :(得分:16)

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

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

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

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

答案 1 :(得分:6)

使用boundingBox()

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

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

答案 2 :(得分:4)

当前接受的答案包括等待,以使元素显示可见。

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

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

然后我们可以通过检查bottomtopheightwidth属性是否未设置为{{1}来验证边界框是否可见}(这也会过滤将display设置为0的元素。)

none

答案 3 :(得分:2)

一个是通过检查其显示样式值。 第二个是通过检查它的高度,对于exp,如果元素是offsetHeight元素的子元素,0将是opacity: 0,因此你知道尽管显示值很大,但该元素仍然不可见。 const isNotHidden = await page.$eval('#menu', (elem) => { return window.getComputedStyle(elem).getPropertyValue('display') !== 'none' && elem.offsetHeight }); 不被视为隐藏元素,因此我们不会检查它。

elem.offsetWidth

你也可以检查<div id=<%# Eval("UnitName") %>>并且在进行任何计算之前都没有坏,检查元素是否存在。

答案 4 :(得分:0)

显然,这是jQuery的工作方式:

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

答案 5 :(得分:0)

如果只想知道某个元素是否可见,则可以使用此功能。在调用此函数之前,应确保页面已准备就绪。您可以通过在希望显示的其他元素上使用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
}

答案 6 :(得分:0)

此代码绝对可以帮助您。 基本上,这意味着该元素已经在页面上可用,但尚不可见,或者在CSS中不可见,显示属性设置为none或可见性被隐藏。现在,在编写测试时,我们假设一旦元素可用,就对其进行操作,例如单击或键入。但是由于此元素尚不可见,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;
}

答案 7 :(得分:0)

pandas.Series.str.extract

答案 8 :(得分:0)

也许您可以使用elementHandle.boundingBox()(感谢@huypham的想法)

它将返回一个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)
        });
      }

答案 9 :(得分:0)

根据剧作家的逻辑检查元素是否可见-https://github.com/microsoft/playwright/blob/master/src/server/injected/injectedScript.ts#L120-L129

function isVisible(element: Element): boolean {
    // Note: this logic should be similar to waitForDisplayedAtStablePosition() to avoid surprises.
    if (!element.ownerDocument || !element.ownerDocument.defaultView)
      return true;
    const style = element.ownerDocument.defaultView.getComputedStyle(element);
    if (!style || style.visibility === 'hidden')
      return false;
    const rect = element.getBoundingClientRect();
    return rect.width > 0 && rect.height > 0;
  }

答案 10 :(得分:-1)

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

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

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