javascript 如何检查元素是否在视口中?

jfgube3f  于 2023-01-16  发布在  Java
关注(0)|答案(4)|浏览(116)

我有一个类似数组的节点对象(它是一个旋转木马),它们的顺序是随机生成的,每次页面刷新,playwright发现所有的元素都是可见的,但其中一些元素在视口之外(基于收到的错误)。我需要确保,当试图单击它时,该元素在视口之内,否则我会收到一个错误,说明该元素在视口之外。
如何确定类似阵列的对象的随机拾取节点元素是否确实在视口中?

gz5pxeao

gz5pxeao1#

遗憾的是,剧作家还没有像 puppet 戏中的isInterSectingViewport这样的方法。(likethis
所以剧作家的作者在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中isInterSectingViewport方法的实现

wqnecbli

wqnecbli2#

使用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()
})
euoag5mw

euoag5mw3#

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);
bwntbbo3

bwntbbo34#

除了cardinalX answer之外,您还可以使用page.waitForFunction创建帮助器函数,以等待元素进入视区

import { Page } from '@playwright/test';

export const waitToBeInViewport = async (
  page: Page,
  selector: string,
) => page.waitForFunction(async (selectorParam: string) => {
  const element = document.querySelector(selectorParam);
  const visibleRatio: number = await new Promise((resolve) => {
    const observer = new IntersectionObserver((entries) => {
      resolve(entries[0].intersectionRatio);
      observer.disconnect();
    });
    observer.observe(element);
    requestAnimationFrame(() => { });
  });
  return visibleRatio > 0; // where 0 - element has just appeared, and 1 - element fully visible;
}, selector);

相关问题