Let's first look at the introduction in MDN:
The Intersection Observer interface provides an asynchronous way to observe the intersection state of the target element with its ancestor element or top-level document viewport, which is called root.
Directly into the topic, Intersection Observer translates as "cross-observer". Its task is to monitor whether the target element and the specified parent element (user-specified, default is viewport) are cross-acting. Simple understanding is to monitor whether the target element enters or leaves the inside of the specified parent element (understand this sentence). I seem to be driving, but you don't have any evidence.
The following target elements are abbreviated as target, designated parent elements are abbreviated as father, crossover behavior is abbreviated as crossover, and viewport is abbreviated as window (vi)
There will be a motion picture below. First, bear with it! ____________
usage
1. Constructor
new IntersectionObserver(callback, options);
2. callback
A cross callback occurs, accepts an entries parameter, returns the set of targets that are currently monitored and crossed (an example of why "and crossed" occurs later):
new IntersectionObserver(entries => { entries.forEach(item => console.log(item)); // ... });
Let's see what common attributes are included in item:
attribute | Explain | |
---|---|---|
boundingClientRect | spatial information | |
intersectionRatio | Proportion of visible regions of elements | |
isIntersecting | It is literally understood as crossing and can be used to determine whether an element is visible or not. | |
target | Target node, just like event.target |
Note: The page initialization triggers a callback, entries for all monitored target sets
3. options
As the name implies, it is a configuration parameter, object type, not required to fill in, common attributes are as follows:
attribute | Explain | |
---|---|---|
root | Specify parent element, default window | |
rootMargin | The offset value triggering crossover is "0px 0px 0px 0px 0px 0px 0px" by default (upper left and lower right, positive number diffuses outward, negative number shrinks inward) |
new IntersectionObserver(callback, { root: document.querySelector("xx"), rootMargin: "0px 0px -100px 0px" });
If rootMargin is set to "20px 0px 30px 30px 30px", then the element is switched to visible state before reaching the window:
4. Common methods
Name | Explain | parameter |
---|---|---|
observe | Start listening for a target element | node |
unobserve | Stop listening on a target element | node |
takeRecords | Returns a collection of all monitored target elements | |
disconnect | Stop all listening |
Example
1. Suppose there is a class="box" box on the page and the parent element is a window:
let box = document.querySelector(".box"); let observer = new IntersectionObserver(entries => { entries.forEach(item => { let tips = item.isIntersecting ? "Into the interior of the parent element" : "Out of the parent element's interior"; console.log(tips); }); }); observer.observe(box); // Listen on a box
The results are as follows:
2. Suppose there are several boxes with class="box" on the page and the parent element is a window:
let box = document.querySelectorAll(".box"); let observer = new IntersectionObserver(entries => console.log(`Cross-over behavior occurs, and the target elements are ${entries.length}individual`)); box.forEach(item => observer.observe(item)); // Listening for multiple box es
When all boxes are the same distance from the top of the window, the effect is as follows:
When all boxes are different from the top of the window, the effect is as follows:
Why do we take the above two cases for example, because entries are returning to the target set that has been monitored and crossed. In the first case, everyone crosses together, and the length of the set returned each time is three. In the second case, each target crosses in turn, and only one triggers at present. The length of the collection returned each time is only 1.
3. Specify the parent element
Suppose html is as follows:
<div class="parent"> <div class="child"></div> </div>
Then begin listening:
let child = document.querySelector(".child"); let observer = new IntersectionObserver(entries => { entries.forEach(item => { console.log(item.isIntersecting ? "So" : "Invisible"); }); }, { root: document.querySelector(".parent") }); observer.observe(child); // Start listening on child ren
The results are as follows:
practical application
1. Lazy loading of pictures
In the past, it used to listen to the browser scroll, then traverse to get the spatial information of each picture, and then judge some location information to load the picture; now it only needs to be handed to the cross-observer to do:
let images = document.querySelectorAll("img.lazyload"); let observer = new IntersectionObserver(entries => { entries.forEach(item => { if (item.isIntersecting) { item.target.src = item.target.dataset.origin; // Start loading pictures observer.unobserve(item.target); // Stop listening for images that have started loading } }); }); images.forEach(item => observer.observe(item));
The results are as follows:
Slow down the speed of the network:
Set the root Margin offset value to "0px 0px-100px 0px" (bottom shrinks inward):
Another advantage of this method is that when there is a horizontal scrollbar at a node on the page, it can handle it freely as follows:
Traditional lazy loading only monitors the scroll of global scrollbars, and such small details can not be achieved (the traditional method is not to determine whether the target appears in the window, so the horizontal images will be loaded together, even if you do not slide to the left), so this is also a major advantage of cross-observers.
2. Bottom Touch
We put a reference element at the bottom of the list and let the cross-observer listen.
Assume that the html structure is as follows:
<!-- Data List --> <ul> <li>index</li> </ul> <!-- Reference element --> <div class="reference"></div>
Then listen for reference elements:
new IntersectionObserver(entries => { let item = entries[0]; // Take the first one. There's only one. if (item.isIntersecting) console.log("Scroll to the bottom and start requesting data"); }).observe(document.querySelector(".reference")); // Listen for Reference Elements
The results are as follows:
3. Roof suction
There are many ways to achieve element ceiling, such as position: sticky of css, which has poor compatibility; if it is also convenient to implement with cross-observer, it also needs to put a reference element.
Assume that the html structure is as follows:
<!-- Reference element --> <div class="reference"></div> <nav>I can suck the top.</nav>
Suppose the scss code is as follows:
nav { &.fixed { position: fixed; top: 0; left: 0; width: 100%; } }
Start listening:
let nav = document.querySelector('nav'); let reference = document.querySelector(".reference"); new IntersectionObserver(entries => { let item = entries[0]; let top = item.boundingClientRect.top; // When the top value of the reference element is less than 0, that is, at the top of the window, start to suck the top, otherwise remove the top. if (top < 0) nav.classList.add("fixed"); else nav.classList.remove("fixed"); }).observe(reference);
The results are as follows:
But there's a problem. When you roll slowly, you fall into a dead cycle.
To facilitate observation, we add a height and a color to the reference element.
The problem is obvious. When fixed location is added to nav, NAV breaks away from the document stream, natural reference elements fall down, and then cross-over occurs, thus removing fixed location and falling into a dead cycle.
After thinking for a while, the solution is to make the reference element absolutely positioned above nav:
let nav = document.querySelector('nav'); let reference = document.querySelector(".reference"); reference.style.top = nav.offsetTop + "px"; // The following code remains unchanged...
In this way, even if nav is separated from the document stream, it will not affect the location of the reference elements:
4. Animation Show
I believe that many people need this requirement, when an element appears, add an animation to the element, such as gradient, offset, etc.
Assume that the html structure is as follows:
<ul> <li></li> </ul>
Suppose the scss code is as follows:
ul { li { &.show { // Come in on the left by default animation: left 1s ease; // Even numbers come in from the right &:nth-child(2n) { animation: right 1s ease; } } } } @keyframes left { from { opacity: 0; transform: translate(-20px, 20px); // Change right animation to 20px, 20px } to { opacity: 1; } }
Then begin listening:
let list = document.querySelectorAll("ul li"); let observer = new IntersectionObserver(entries => { entries.forEach(item => { if (item.isIntersecting) { item.target.classList.add("show"); // Add the show class name observer.unobserve(item.target); // Remove listening } }); }); list.forEach(item => observer.observe(item));
The results are as follows:
Compatibility
IE is incompatible, but there are Official polyfill✅
Last
It's worth noting that there must be a crossover between the child and the father. If you want to check the crossover between two non-father-son relationships, it's not good. If you think this article is good, please don't forget to point out some comments and concerns.
Communication
The public number "Front End Cosmological Intelligence Agency" will update the latest and practical front-end skills/technical articles from time to time, and will also occasionally have interesting news on the Internet.
Pay attention to the public number, reply to "1" to get the two-dimensional code of Weixin group chat, learn, communicate and fish together