如何使用 Puppeteer 和纯 JavaScript 检查元素是不是可见?
Posted
技术标签:
【中文标题】如何使用 Puppeteer 和纯 JavaScript 检查元素是不是可见?【英文标题】:How can I check that an element is visible with Puppeteer and pure JavaScript?如何使用 Puppeteer 和纯 JavaScript 检查元素是否可见? 【发布时间】:2018-05-22 14:24:31 【问题描述】:我希望使用Puppeteer 和纯 javascript(不是 jQuery)检查 DOM 元素是否可见,我该怎么做?可见是指元素通过 CSS 显示,而不是隐藏(例如 display: none
)。
例如,我可以通过 CSS 规则 display: none
判断我的元素 #menu
是否未被隐藏,方法如下:
const isNotHidden = await page.$eval('#menu', (elem) =>
return elem.style.display !== 'none'
)
我如何才能确定元素是否隐藏,而不仅仅是通过display: none
?
【问题讨论】:
我不知道它对其他隐藏方法的效果如何,但elem.getBoundingClientRect()
返回了您可以测试的独特数据。
@AuxTaco usingelem.getBoundingClientRect()
在console.log 上返回
,无论元素是否准备好:(
由于Puppeteer总是可以运行正常的JS,规范线程Check if element is visible in DOM应该被链接,因为它有大量的资源可以通过Puppeteer中的.evaluate()
使用。
@PayamB。您是否尝试返回JSON.stringify(elem.getBoundingClientRect())
?它可能很重要的原因是 elem.getBounding...
是只读的 DOMRect
而不是普通对象,因此 Puppeteer 的序列化似乎受到影响并且没有捕获完整的对象。
【参考方案1】:
One 是通过检查其显示样式值。
第二是检查它的高度,如果元素是display: none
元素的子元素,则offsetHeight
将是0
,因此您知道该元素不可见,尽管其显示值。 opacity: 0
不被视为隐藏元素,因此我们不会对其进行检查。
const isNotHidden = await page.$eval('#menu', (elem) =>
return window.getComputedStyle(elem).getPropertyValue('display') !== 'none' && elem.offsetHeight
);
您也可以检查elem.offsetWidth
,并且在任何计算之前都不错,检查元素是否存在。
【讨论】:
和"window" var在哪里定义? @pabgaran window 对象表示一个包含 DOM 文档的窗口; getComputedStyle。您可以将窗口缓存到变量 ofc 中,但它是一个全局对象 你是对的。我是木偶的初学者。所有这些代码都在“导航器”中运行,因此窗口、文档等始终可用。 这个解决方案节省了我的时间,除了我检查了元素的高度。【参考方案2】:我发现 Puppeteer 有一个用于此目的的 API 方法:Page.waitForSelector,通过它的visible
选项。我不知道后一种选择,但它可以让您等到元素可见。
await page.waitForSelector('#element',
visible: true,
)
相反,您可以通过hidden
选项等待隐藏元素。
我认为这是关于 Puppeteer API 的惯用答案。感谢 Colin Cline,因为我认为他的回答可能作为通用 JavaScript 解决方案有用。
【讨论】:
如果元素不可见,这将抛出。如果元素不可见是完全可以接受的,那么投掷是不合适的。我希望开发人员停止为正常行为抛出异常,只返回一个类似 null 的值! @Gerry 这正是我的问题,我想检查元素,然后在元素尚未准备好时根据该元素做一些事情,但是在查找元素时它会抛出并导致应用程序崩溃跨度> 问题是如何测试一个元素是否可见,而不是等待它被添加到 DOM 中然后变得可见,这就是这个“接受”的解决方案所做的。【参考方案3】:我会使用 @aknuds1 的方法,但您也可以执行以下操作。
expect((await page.$('#element')) !== null).toEqual(true)
如果您正在异步获取资源,请注意上述预期可能不会通过,因为它不会等待更改反映在 UI 上。这就是为什么这种方法在这种情况下可能不是首选的原因。
【讨论】:
@Gerry 你完全错了。在发表评论之前,请仔细阅读问题。 看来您的答案是期望使用 puppeteer 测试框架,例如 jest-puppeteer,而 OP 没有指定他们正在测试。【参考方案4】:显然这是 jQuery 的做法:
visible = await page.evaluate((e) => e.offsetWidth > 0 && e.offsetHeight > 0, element)
【讨论】:
【参考方案5】:如果你只是想知道一个元素是否可见,那么你可以使用这个函数。在调用此函数之前,您应该确保页面已准备就绪。您可以通过在您希望可见的其他元素上使用 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】:当前接受的答案涉及等待元素出现并变得可见。
如果我们对等待元素不感兴趣,只是想测试元素的可见性,我们可以使用getComputedStyle()
和getBoundingClientRect()
的组合来测试元素是否可见。
我们可以先检查visibility
没有设置为hidden
。
然后我们可以通过检查bottom
、top
、height
和width
属性未设置为0
来验证边界框是否可见(这将过滤掉具有@的元素987654324@ 也设置为 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);
);
【讨论】:
【参考方案7】:使用boundingBox()
此方法返回元素的边界框(相对于主框架),如果元素不可见,则返回 null。
API:https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#elementhandleboundingbox
【讨论】:
【参考方案8】:此代码绝对可以帮助您。 它基本上意味着该元素已经在页面上可用但尚不可见或在 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;
【讨论】:
【参考方案9】:const firstName= await page.$('[name=firstName]')
expect(firstName!=null).equal(true)
【讨论】:
【参考方案10】:也许你可以使用elementHandle.boundingBox()
(感谢@huypham 的想法)
它将返回一个显示元素边界框的 Promise(相对于主框架),如果元素不可见,则返回 null。
sn-p 示例:
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)
);
【讨论】:
【参考方案11】:基于剧作家检查元素是否可见的逻辑 - 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;
【讨论】:
以上是关于如何使用 Puppeteer 和纯 JavaScript 检查元素是不是可见?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 webpack 捆绑 puppeteer 进行生产部署?