Article directory
1. Introduction
Intersection Observer API
Provides a method to monitor whether the target element is displayed to the viewport ( viewport
) . Common demand scenarios:
- Lazy loading of images
- scroll animation
- …
For the above requirements, in the past , events were generally monitored and methods were used to obtain the location information of the target elementscroll
getBoundingClientRect()
. Due to monitoring scroll
events, reflow is continuously triggered , which has a certain impact on performance. However, it can be solved through function throttling , but getBoundingClientRect()
the impact of this method on performance cannot be effectively optimized.
! ! ! Therefore, in order to solve the above problems, the browser introduced it IntersectionObserver API
. Since the method is asynchronous, it does not affect the execution efficiency of the main thread.
2. Compatibility
It is compatible with the mainstream browsers on the market. Generally speaking, it is optimistic. However, for the sake of the rigor of the code, let’s make a simple judgment:
if (window?.IntersectionObserver) {
let io = new IntersectionObserver(callback, options)
io.observe(targetElement)
}
3. Built-in methods/properties
let io = new IntersectionObserver(entries => {
// IntersectionObserverEntry 作为一个参数返回
console.log(entries)
}, {
root: null, rootMargin: '0px 0px', threshold: [0.5, 1] })
// 开始监听
io.observe(targetElement)
// 停止监听
io.unobserve(targetElement)
// 结束监听器
io.disconnect()
As we can see above, IntersectionObserver
it receives a callback function and an object options
as parameters.
IntersectionObserverEntry
entries
The instance is passed to the callback function as a parameter, providing information about the element at that time.
See entries
what properties it has:
Attributes | effect |
---|---|
boundingClientRect |
Information about the rectangular area of the target element |
intersectionRatio |
The visible proportion of the target element, that is, the proportion of , is 1 when it is completely visible, and is less than or equal to 0 when it intersectionRect is boundingClientRect completely invisible. |
intersectionRect |
Information about the intersection area between the target element and the viewport (or root element) |
isIntersecting |
Whether the target target element has been converted to the intersected state ( true ) or to the disjoint state ( false ) |
rootBounds |
Information about the rectangular area of the root element, getBoundingClientRect() the return value of the method, if there is no root element (that is, scrolling directly relative to the viewport), it is returnednull |
target |
The target element being observed is a DOM node object |
time |
The time when the visibility changed, which is a high-precision timestamp in milliseconds |
API
Provided methods/properties:
methods/properties | effect |
---|---|
root |
Root element, default viewport ( viewport ) |
rootMargin |
Offset relative to the root element, default value is "0px 0px" |
threshold |
Gate value that triggers the callback function, in ascending order, default 0, optional: [0, 0.25, 0.5, 0.75, 1] |
observe(targetElement) |
Start monitoring, must transmit targetElement , can observe multiple nodes at the same time |
unobserve(targetElement) |
Stop monitoring, must transmittargetElement |
takeRecords() |
IntersectionObserverEntry Returns an array of objects for all listening targets and stops listening on them |
disconnect() |
Stop the listener from working |
4. Use
Let’s write a scrolling update element content/style function here:
HTML:
<div class="container">
<div class="item" data-id="1">元素1:不可见</div>
<div class="item" data-id="2">元素2:不可见</div>
<div class="item" data-id="3">元素3:不可见</div>
<div class="item" data-id="4">元素4:不可见</div>
<div class="item" data-id="5">元素5:不可见</div>
</div>
JS:
Modify the text/background color when the target element is fully exposed/not fully exposed
<script>
if (window?.IntersectionObserver) {
let items = [...document.getElementsByClassName('item')] // 解析为真数组,也可用 Array.prototype.slice.call()
let io = new IntersectionObserver(entries => {
entries.forEach(item => {
// intersectionRatio === 1说明该元素完全暴露出来
if (item.intersectionRatio === 1) {
item.target.style.backgroundColor = 'deeppink'
item.target.innerHTML = `元素${
item.target.getAttribute('data-id')}:完全可见`
} else {
item.target.style.backgroundColor = 'deepskyblue'
item.target.innerHTML = `元素${
item.target.getAttribute('data-id')}:不可见`
}
})
}, {
root: null,
rootMargin: '0px 0px',
threshold: 1 // 阀值设为1,当只有比例达到1时才触发回调函数
})
items.forEach(item => io.observe(item))
}
</script>