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

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

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

【问题讨论】:

    标签: puppeteer viewport 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()
        })
        

        【讨论】:

          猜你喜欢
          • 2021-08-04
          • 1970-01-01
          • 1970-01-01
          • 2015-09-05
          • 1970-01-01
          • 2021-12-04
          • 2022-09-24
          • 2019-02-12
          • 2020-08-10
          相关资源
          最近更新 更多