剧作家 - 如何检查元素是不是在视口中?

Posted

技术标签:

【中文标题】剧作家 - 如何检查元素是不是在视口中?【英文标题】:Playwright - how to check if element is in viewport?剧作家 - 如何检查元素是否在视口中? 【发布时间】:2021-06-03 05:53:47 【问题描述】:

我有一个类似数组的节点对象(它是一个轮播),它们的顺序是在每次页面刷新时随机生成的,playwright 发现所有元素都是可见的,但其中一些在视口之外(基于收到错误)。我需要确保在尝试单击该元素时该元素在视口内,否则我会收到错误消息,指出该元素在外面。

如何判断一个随机选取的类数组对象的节点元素是否真的在视口内?

【问题讨论】:

【参考方案1】:
const firstId = "#someId"; 

// it happens that I am evaluating in a frame, rather than page 
const result = await frame.evaluate((firstId) => 

  // define a function that handles the issue
  // returns true if element is within viewport, false otherwise 
  function isInViewport(el) 

    // find element on page 
    const element = document.querySelector(el); 

    const rect = element.getBoundingClientRect();
    return (
      rect.top >= 0 &&
      rect.left >= 0 &&
      rect.bottom <=
        (window.innerHeight || document.documentElement.clientHeight) &&
      rect.right <=
        (window.innerWidth || document.documentElement.clientWidth)
    );
  ; 

  return isInViewport(firstId); 

, firstId);



// back to node context 
console.log(result); 

【讨论】:

【参考方案2】:

不幸的是,Playwright 在 Puppeteer 中还没有类似 isInterSectingViewport 的方法。(likethis)

所以 Playwright 的作者在 Slack 社区帮助我(你可以在官方网站上找到它)。

    const result = await page.$eval(selector, async element => 
      const visibleRatio: number = await new Promise(resolve => 
        const observer = new IntersectionObserver(entries => 
          resolve(entries[0].intersectionRatio);
          observer.disconnect();
        );
        observer.observe(element);
        // Firefox doesn't call IntersectionObserver callback unless
        // there are rafs.
        requestAnimationFrame(() => );
      );
      return visibleRatio > 0;
    );

我使用这种方法的案例: 我想知道,在我单击某个元素后 - 我滚动到另一个元素。不幸的是,boundingBox 方法对我没有帮助。

您也可以将此功能添加到我的 BasePage 类中

/**
     * @returns !Promise<boolean>
     */
  isIntersectingViewport(selector: string): Promise<boolean> 
    return this.page.$eval(selector, async element => 
      const visibleRatio: number = await new Promise(resolve => 
        const observer = new IntersectionObserver(entries => 
          resolve(entries[0].intersectionRatio);
          observer.disconnect();
        );
        observer.observe(element);
        // Firefox doesn't call IntersectionObserver callback unless
        // there are rafs.
        requestAnimationFrame(() => );
      );
      return visibleRatio > 0;
    );
  

附: 其实除了一行之外的所有代码都取自GitHub Puppeteer中方法isInterSettingViewport的实现

【讨论】:

【参考方案3】:

使用 css 选择器检查元素是否在视口中:

import  test, expect, devices  from '@playwright/test'

const url = 'https://example.com'
const selector = 'h1'

test.use(
    headless: false,
    browserName: 'webkit',
    ...devices['iPhone 13 Mini'],
)

test('visibility', async ( page ) => 
    await page.goto(url)
    const box = await page.locator(selector).boundingBox() // it contains x, y, width, and height only
    let isVisible = await page.evaluate((selector) => 
        let isVisible = false
        let element = document.querySelector(selector)
        if (element) 
            let rect = element.getBoundingClientRect()
            if (rect.top >= 0 && rect.left >= 0) 
                const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0)
                const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0)
                if (rect.right <= vw && rect.bottom <= vh) 
                    isVisible = true
                
            
        
        return isVisible
    , selector)
    await expect(isVisible).toBeTruthy()
)

【讨论】:

以上是关于剧作家 - 如何检查元素是不是在视口中?的主要内容,如果未能解决你的问题,请参考以下文章

如何获得剧作家的元素集合?

Jquery检查元素在视口中是不是可见[重复]

如何使用剧作家或柏树选择蚂蚁设计选择选项

如何从剧作家那里读取文本框值

OpenOffice.org 作家 [关闭]

Imdb上所有电影名称、演员、导演、作家的列表