intersectionobserverapi
Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
The IntersectionObserver API (IntersectionObserver API) provides developers with a way to asynchronously monitor the intersecting status of a target element with its ancestors or viewport. Ancestor elements and viewports are called roots.
Simply put, IntersectionApi functions are used to judge whether a target element changes its ancestor or window crossover state
It is used to detect that the target element and root element have just started to cross and the target element and root element have just started to not cross
The illustration is as follows:
The IntersectionObserver API is asynchronous and does not trigger with the rolling synchronization of the target element. That is, the observer is executed only when the thread is idle. This means that the observer has a very low priority and only executes when the browser is idle after other tasks have been completed.
Basic API usage
// Callback is a callback that is triggered when the visibility of the monitored element changes
// Options is an optional configuration parameter object. Default values exist when no configuration is performed
const observer = new IntersectionObserver(callback, options)
// Callback received by IntersectionObserver will be called back in three cases
// 1. The corresponding element is added to the listener queue using the observe method
// 2. The corresponding element and the browser visual window just start to cross -- enter the visual window
// 3. The corresponding element and the browser visual window are changed from existing crossover to initially non-crossover - completely leaving the visual window
Copy the code
// Add a listener to the target element. When the target element changes, the callback is triggered
// Observe () is a DOM node object. Call this method multiple times if you want to observe multiple nodes
observer.observe(element);
// Remove a listener. After removing it, the target element's cross state changes and the callback function is no longer triggered
observer.unobserve(element)
// Stop all listening
observer.disconnect();
Copy the code
IntersectionObserverEntry
/ / IntersectionObserverEntry object target information to simplify the following to display an element
{
// The value of time is a timestamp representing the time between the observer's instantiation and the change in the cross state of the detected object
Example: if the value is 1000, it indicates that the intersecting state of target elements changes after 1 second of instantiation of IntersectionObserver
time: 78463997.025.// The rectangle information corresponding to the root element (that is, the return value from calling getBoundingClientRect())
// If there is no root element (i.e. scrolling directly relative to the viewport), null is returned
rootBounds: null.// Rectangle information for the target element
boundingClientRect: DOMRectReadOnly { / *... * / },
// Rectangle information about the area where the target element intersects with the viewport (or root root element)
intersectionRect: DOMRectReadOnly { / *... * / },
// Whether the target element is currently visible Boolean is visible as true
isIntersecting: true.// Visible ratio of target element --> [0, 1]
intersectionRatio: 1.// The object being listened on is a DOM element
target: div#target.target
}
Copy the code
The relationship of the above rectangle information is as follows:
Option option
The second argument to the IntersectionObserver constructor is a configuration object that can set the following properties: IntersectionObserver IntersectionObserver
threshold
The threshold property determines when the callback is triggered. The value is an array, and each array entry represents a threshold value
The callback is triggered when the percentage of the target element’s area that intersects the root element reaches or crosses these specified thresholds
The default value of threshold is [0, 1], which means that the callback function is triggered only when you start to enter or completely leave the view area
rootMargin
To increase or decrease the size of the window, use CSS definitions with the values of top, right,bottom, and left at 10px, 10px, 10px, and 20px.
root
The root attribute specifies the container node on which the target element is located (the root element). Note that the container element must be the ancestor node of the target element
A simple example
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>Document</title>
<style>
body {
height: 200vh;
padding: 0 30px;
}
.target {
width: 300px;
height: 300px;
margin-top: 2000px;
background-color: red;
}
</style>
</head>
<body>
<div id="target" class="target"></div>
<script>
// Create IntersectionObserver instance object -- the argument is a callback
/ / entries is IntersectionObserverEntry array of objects
// Listen on the number of elements, the length of the array
const observer = new IntersectionObserver(entries= > {
entries.forEach(entry= > {
console.log(entry.isIntersecting ? 'Div in viewable area' : 'Div is not in viewable area')})})// Add a listener for an element
observer.observe(document.getElementById('target'))
</script>
</body>
</html>
Copy the code
Application scenarios
Lazy load
We want some static resources (such as images) to be loaded only when the user scrolls down into the viewport to save bandwidth and improve web performance. This is known as “lazy loading”.
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>lazy load</title>
<style>
body {
height: 200vh;
padding: 0 30px;
}
.target {
width: 300px;
height: 300px;
margin-top: 2000px;
}
</style>
</head>
<body>
<img
id="target"
class="target"
data-src="https://s6.jpg.cm/2021/10/29/I3Pa3D.jpg"
src="https://img.alicdn.com/tps/i3/T1QYOyXqRaXXaY1rfd-32-32.gif"
/>
<script>
const observer = new IntersectionObserver(entries= > {
entries.forEach(entry= > {
if (entry.isIntersecting) {
entry.target.src = entry.target.getAttribute('data-src')
entry.target.removeAttribute('data-src')
observer.unobserve(entry.target)
}
})
})
observer.observe(document.getElementById('target'))
</script>
</body>
</html>
Copy the code
Infinite Scroll
For infinite scrolling, it’s best to have a page end column (aka sentinels) at the bottom of the page.
Once the footer is visible, the user reaches the bottom of the page and loads a new entry in front of the footer.
The advantage of this approach is that IntersectionObserver only needs to call the Observe method once to listen on an object to perform relevant functions
index.html
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="Width = device - width, initial - scale = 1.0">
<title>infinite scroll</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div id="container" class="container">
<div id="loading">Data loading...</div>
</div>
<script src="./index.js"></script>
</body>
</html>
Copy the code
index.css
html.body {
height: 100%;
font-size: 20px;
}
#loading {
text-align: center;
}
.unit {
height: 120px;
border: 1px solid black;
text-align: center;
}
.container {
max-width: 300px;
height: 500px;
margin: 0px auto;
overflow: auto;
border: 5px solid # 000;
}
Copy the code
index.js
let count = 0
const container = document.getElementById('container')
const observer = new IntersectionObserver(entries= > {
if (entries[0].isIntersecting) {
const fragment = document.createDocumentFragment()
for (let i = 0; i < 5; i++) {
const dv = document.createElement('div')
dv.className = 'unit'
dv.innerHTML = The first `${count++ + 1}Element `
fragment.appendChild(dv)
}
container.insertBefore(fragment, entries[0].target)
}
})
observer.observe(document.getElementById('loading'))
Copy the code