Home  >  Article  >  Web Front-end  >  How does vue determine whether an element is in the visible area?

How does vue determine whether an element is in the visible area?

青灯夜游
青灯夜游Original
2022-11-29 19:09:086242browse

Three methods: 1. Use offsetTop and scrollTop to obtain the position of the element, and determine whether it is less than or equal to viewPortHeight (view port distance). 2. Use getBoundingClientRect() to judge, the syntax is "element object.getBoundingClientRect()". 3. Use IntersectionObserver to judge, just check whether the specified element and the visible area overlap.

How does vue determine whether an element is in the visible area?

The operating environment of this tutorial: windows7 system, vue3 version, DELL G3 computer.

What is the visible area

The visible area is the area visible to the naked eye on the device we use to browse the web, as shown below

How does vue determine whether an element is in the visible area?

In daily development, we often need to determine whether the target element is within the view window or the distance from the view window is less than a value (such as 100 px), so as to implement some common functions, such as:

  • Lazy loading of images
  • Infinite scrolling of lists
  • Calculate the exposure of advertising elements
  • Preloading of clickable links

Three ways to determine whether an element is in the visible area

To determine whether an element is in the visible area, we commonly use three methods:

  • offsetTop, scrollTop

  • getBoundingClientRect

  • Intersection Observer

Method 1 , offsetTop, scrollTop

##offsetTop, the pixel distance between the top outer border of the element and the top inner border of the containing element, othersoffset The properties are shown in the figure below:

How does vue determine whether an element is in the visible area?

Let’s learn more about

clientWidth, clientHeight:

  • clientWidth: The width of the element content area plus the left and right padding width, that is, clientWidth = content padding
  • clientHeight: The height of the element content area plus The height of the top and bottom padding, that is, clientHeight = content padding
Here you can see that the

client elements do not include margins

Finally, the attributes of the

scroll series are as follows:

  • scrollWidth and scrollHeight are mainly used to determine the actual content of the element. The size

  • scrollLeft and scrollTop properties can both determine the current scrolling state of the element and set the scroll position of the element

    • Vertical scroll
    • scrollTop > 0
    • Horizontal scroll
    • scrollLeft > 0
  • Set the element's

    scrollLeft and scrollTop to 0 to reset the element's scroll position

Note

    The above attributes are read-only, and each access must be restarted
Let’s take a look at how to implement the judgment:

The formula is as follows:

el.offsetTop - document.documentElement.scrollTop <= viewPortHeight
Code implementation:

function isInViewPortOfOne (el) {
    // viewPortHeight 兼容所有浏览器写法
    const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight 
    const offsetTop = el.offsetTop
    const scrollTop = document.documentElement.scrollTop
    const top = offsetTop - scrollTop
    return top <= viewPortHeight
}

Method 2: getBoundingClientRect

The return value is a

DOMRect object with left, top, right, bottom, The x, y, width, and height properties. [Learning video sharing: vue video tutorial, web front-end video]

const target = document.querySelector(&#39;.target&#39;);
const clientRect = target.getBoundingClientRect();
console.log(clientRect);

// {
//   bottom: 556.21875,
//   height: 393.59375,
//   left: 333,
//   right: 1017,
//   top: 162.625,
//   width: 684
// }
The relationship diagram corresponding to the attributes is as follows:

How does vue determine whether an element is in the visible area?

When the page scrolls, the

top and left attribute values ​​will change accordingly

If an element is in If it is within the window, then it must meet the following four conditions:

    top is greater than or equal to 0
  • left is greater than or equal to 0
  • bottom is less than or equal to the window height
  • right is less than or equal to the window width
The implementation code is as follows:

function isInViewPort(element) {
  const viewWidth = window.innerWidth || document.documentElement.clientWidth;
  const viewHeight = window.innerHeight || document.documentElement.clientHeight;
  const {
    top,
    right,
    bottom,
    left,
  } = element.getBoundingClientRect();

  return (
    top >= 0 &&
    left >= 0 &&
    right <= viewWidth &&
    bottom <= viewHeight
  );
}

方法3:Intersection Observer

Intersection Observer 即重叠观察者,从这个命名就可以看出它用于判断两个元素是否重叠,因为不用进行事件的监听,性能方面相比getBoundingClientRect会好很多

使用步骤主要分为两步:创建观察者和传入被观察者

创建观察者

const options = {
  // 表示重叠面积占被观察者的比例,从 0 - 1 取值,
  // 1 表示完全被包含
  threshold: 1.0, 
  root:document.querySelector(&#39;#scrollArea&#39;) // 必须是目标元素的父级元素
};

const callback = (entries, observer) => { ....}

const observer = new IntersectionObserver(callback, options);

通过new IntersectionObserver创建了观察者 observer,传入的参数 callback 在重叠比例超过 threshold 时会被执行`

关于callback回调函数常用属性如下:

// 上段代码中被省略的 callback
const callback = function(entries, observer) { 
    entries.forEach(entry => {
        entry.time;               // 触发的时间
        entry.rootBounds;         // 根元素的位置矩形,这种情况下为视窗位置
        entry.boundingClientRect; // 被观察者的位置举行
        entry.intersectionRect;   // 重叠区域的位置矩形
        entry.intersectionRatio;  // 重叠区域占被观察者面积的比例(被观察者不是矩形时也按照矩形计算)
        entry.target;             // 被观察者
    });
};
传入被观察者

通过 observer.observe(target) 这一行代码即可简单的注册被观察者

const target = document.querySelector(&#39;.target&#39;);
observer.observe(target);

案例分析

实现:创建了一个十万个节点的长列表,当节点滚入到视窗中时,背景就会从红色变为黄色

Html结构如下:

<div class="container"></div>

css样式如下:

.container {
    display: flex;
    flex-wrap: wrap;
}
.target {
    margin: 5px;
    width: 20px;
    height: 20px;
    background: red;
}

container插入1000个元素

const $container = $(".container");

// 插入 100000 个 <div class="target"></div>
function createTargets() {
  const htmlString = new Array(100000)
    .fill(&#39;<div class="target"></div>&#39;)
    .join("");
  $container.html(htmlString);
}

这里,首先使用getBoundingClientRect方法进行判断元素是否在可视区域

function isInViewPort(element) {
    const viewWidth = window.innerWidth || document.documentElement.clientWidth;
    const viewHeight =
          window.innerHeight || document.documentElement.clientHeight;
    const { top, right, bottom, left } = element.getBoundingClientRect();

    return top >= 0 && left >= 0 && right <= viewWidth && bottom <= viewHeight;
}

然后开始监听scroll事件,判断页面上哪些元素在可视区域中,如果在可视区域中则将背景颜色设置为yellow

$(window).on("scroll", () => {
    console.log("scroll !");
    $targets.each((index, element) => {
        if (isInViewPort(element)) {
            $(element).css("background-color", "yellow");
        }
    });
});

通过上述方式,可以看到可视区域颜色会变成黄色了,但是可以明显看到有卡顿的现象,原因在于我们绑定了scroll事件,scroll事件伴随了大量的计算,会造成资源方面的浪费

下面通过Intersection Observer的形式同样实现相同的功能

首先创建一个观察者

const observer = new IntersectionObserver(getYellow, { threshold: 1.0 });

getYellow回调函数实现对背景颜色改变,如下:

function getYellow(entries, observer) {
    entries.forEach(entry => {
        $(entry.target).css("background-color", "yellow");
    });
}

最后传入观察者,即.target元素

$targets.each((index, element) => {
    observer.observe(element);
});
可以看到功能同样完成,并且页面不会出现卡顿的情况

The above is the detailed content of How does vue determine whether an element is in the visible area?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn