The original, zhuanlan.zhihu.com/p/88767748.

preface

AD dogging and image lazy loading are two very common requirements, the simplest way to implement by listening for Scroll event, but we all know that the scroll event listening callback is executed synchronously, which will affect the UI rendering of JS main thread. And IntersectionObserver is coming soon. Observer is used instead of IntersectionObserver in the article.

Let’s start with an official declaration (MDN)

The Intersection Observer API provides a way to asynchronously observe changes in the Intersection of a target element with an ancestor element or a top-level document viewport.

Key points: asynchrony, intersection, variation.

use

Here’s another official declaration (MDN) about its purpose. The Intersection Observer API is available here if you’re not happy with my reference to the official description

  • Lazy loading of images or other content as the page scrolls.
  • Implement “scrollable” sites, where more content loads directly as users scroll, without turning pages.
  • To calculate AD revenue, detect the exposure of its AD elements.
  • Flexibility to start performing tasks or animations based on whether the user has scrolled to the appropriate area.

usage

It’s also very simple to use.

const callback = entries= > {  
/ /...
}; 
 
const options = {  
  rootdocument.querySelector('#scroll'),
  rootMargin'0px'.threshold: [0]};const observer = new IntersectionObserver(callback, options);  

const ele = document.querySelector('.img');  

observer.observe(ele); 
Copy the code

Root The container node where the target element resides. If root is not specified, the default document is root.

RootMargin The margin around the root element, similar to the MARGIN property of CSS. Notice that this unit is px

Threshold can be either a number or an array. The value ranges from 0 to 1.

const callback = (entries, observer) = > {   
  entries.forEach(entry= > {  
    // entry.boundingClientRect
    // entry.intersectionRatio
    // entry.intersectionRect
    // entry.isIntersecting
    // entry.rootBounds
    // entry.target
    // entry.time
  });  

};
Copy the code

Entry.boundingclientrect Specifies the region information of the target element, the return value of getBoundingClientRect()

Entry. intersectionRatio Indicates the visibility ratio of target elements

Entry. intersectionRect Intersects the target element and the root element

Entry. Whether isIntersecting enters the visible area

RootBounds Rectangular area of the root element

Entry. target The object to be observed, which is a DOM node

Entry. time The time at which visibility changes, the number of milliseconds since the intersection occurred when the page was opened. The accuracy is microseconds.

The above paragraph is also basically from the EXPLANATION of MDN, you asked me what this article does, yes, I am copy&paste porter.

Executable method

Observe, create an observe object.

const target = document.querySelector('#listItem');  
observer.observe(target);  
Copy the code

Unobserver, unobserve objects.

observer.unobserve(target);
Copy the code

TakeRecords, return a IntersectionObserverEntry array of objects.

const records = observer.takeRecords(); 
Copy the code

The target element of each object contains information about each intersection. TakeRecords is synchronous, and the callback from IntersectionObserver is asynchronous. Moreover, the maximum callback time of IntersectionObserver is 100ms, so the callback will be executed within 1-100ms. If an asynchronous callback is executed, takeRecords() returns an empty data group; if synchronization is executed first, the callback is not executed. There are few usage scenarios.

Disconnect, terminates observation of changes in visibility for all target elements.

observer.disconnect(); 
Copy the code

Switch the Observer from scroll

Github.com/carrollcai/…

Above is a Demo I wrote where scroll and Observer implement the same elements in the trial view and perform a callback effect.

Below I do a simple experiment, to achieve the image preloading. If B is 300px away from the root document, it intersects with the root document. The following code

<body>
  <A>
    <div style="height: 100vh; width: 100%"></div>
    <B></B>
  </A>
</body>
Copy the code
const callback = entries= > {
  entries.forEach(entry= > {
    if (entry.isIntersecting) {
      console.log('B's intersect. '); }})}const options = {
  rootMargin: '0px 0px 300px 0px'
}

const ob = new IntersectionObserver(callback, options);
ob.observe(B);
Copy the code

When the observer is not set to root, the default root document is the observation area. If you set A to overflow: auto; height: 100vh), it will form A separate layer, which will directly cause the rootMargin to fail, because rootMargin is 0px, 300px, 0px, just add 300px root bottom margin, and A has formed its own BFC. So the rootMargin setting will fail. The best way is to remove the scroll interval of A, because in this way, the observation area is the root element, js event mechanism is capture first and then bubble, capture and bubble occur at the same time on the root element, equal to no such process, the performance is optimal. The minimal change is to set the observation region root to A so rootMargin will also work. The reason I used this example is because I wanted to pre-load images, which load images when they are some distance away from the window. I set the observation area as the root element, but the parent layer of the observation target also set the scrolling area, which directly led to the failure of rootMargin. For a time, I suspected that there was something wrong with the API. With the help of a senior official of Zhihu (ID: Ziyunfei). It also wrote an introduction to the Observer in 2016. IntersectionObserver API.

The performance test

One of the masters said, I’m tired of looking up names, you can’t optimize What you can’t measure. Of course, I am too tired to do the performance test, so the title of the article changes from 100% performance improvement by IntersectionObserver to X% performance improvement by IntersectionObserver, and X may be negative.

conclusion

The Observer API was available for Android phones in 2016 and ios in late 2018. Fortunately, Polyfill is available. I have used this API in production, and now the road is smooth without any hindrances.


Writing time: 20191027