滚动到指定位置加载数据—Intersection Observer接口
(Web API ) IntersectionObserver 接口 (从属于Intersection Observer API) 提供了一种异步观察目标元素与其祖先元素或顶级文档视窗 (viewport) 交叉状态的方法。祖先元素与视窗 (viewport) 被称为根 (root)。
当一个IntersectionObserver对象被创建时,其被配置为监听根中一段给定比例的可见区域。一旦 IntersectionObserver 被创建,则无法更改其配置,所以一个给定的观察者对象只能用来监听可见区域的特定变化值;然而,你可以在同一个观察者对象中配置监听多个目标元素。
IntersectionObserverEntry
IntersectionObserverEntry 的实例作为 entries 参数被传递到一个IntersectionObserver 的回调函数中
属性
- IntersectionObserverEntry.boundingClientRect :
返回包含目标元素的边界信息的DOMRectReadOnly. 边界的计算方式与 Element.getBoundingClientRect() 相同。 - IntersectionObserverEntry.intersectionRatio :
返回intersectionRect 与 boundingClientRect 的比例值。 - IntersectionObserverEntry.intersectionRect :
返回一个 DOMRectReadOnly 用来描述根和目标元素的相交区域。 - IntersectionObserverEntry.isIntersecting :
返回一个布尔值,如果目标元素与交叉区域观察者对象 (intersection observer) 的根相交,则返回 true .如果返回 true, 则 IntersectionObserverEntry 描述了变换到交叉时的状态; 如果返回 false, 那么可以由此判断,变换是从交叉状态到非交叉状态。 - IntersectionObserverEntry.rootBounds :
返回一个 DOMRectReadOnly 用来描述交叉区域观察者 (intersection observer) 中的根。 - IntersectionObserverEntry.target :
与根出现相交区域改变的元素 (Element). - IntersectionObserverEntry.time :
返回一个记录从 IntersectionObserver 的时间原点 (time origin) 到交叉被触发的时间的时间戳 (DOMHighResTimeStamp).
entries 图解
- time:发生相交到相应的时间,毫秒。
- rootBounds:根元素矩形区域的信息,如果没有设置根元素则返回 null,图中蓝色部分区域。
- boundingClientRect:目标元素的矩形区域的信息,图中黑色边框的区域。
- intersectionRect:目标元素与视口(或根元素)的交叉区域的信息,图中蓝色方块和粉红色方块相交的区域。
- isIntersecting:目标元素与根元素是否相交,
true
为相交 - intersectionRatio:目标元素与视口(或根元素)的相交比例。
- target:目标元素,图中黑色边框的部分。
使用
当滚动到loading目标元素后显示
import React, { useState, useEffect } from 'react';
import { history } from 'umi';
let Observer;
export default function (props) {
const [state, setState] = useState()
useEffect(() => {
let dom = document.querySelector('#loading')
console.log('进入页面');
if (dom) {
Observer = new IntersectionObserver(function (entries) {
console.log(entries);
...
})
}
//Observer开始监听一个目标元素
Observer.observe(dom)
return () => {
console.log('离开页面');
if (Observer) {
if (dom) {
// 停止监听特定目标元素
Observer.unobserve(dom);
// Observer对象停止监听工作
Observer.disconnect()
}
}
}
}, [])
const handleClick = () => {
history.push('/')
}
return (
<div>
...
<div id='loading' style={{ width: '100px', height: '100px', background: 'red', marginTop: '1000px' }}>loading</div>
</div>
)
}
自定义hook—useObserverHook.js
import { useEffect } from 'react';
let observer;
export default function useObserverHook(ele, callback, watch = []) {
useEffect(() => {
//node目标元素
const node = document.querySelector(ele);
if (node) {
observer = new IntersectionObserver(entries => {
callback && callback(entries)
})
//开始监听目标元素
observer.observe(node)
}
return () => {
if (observer && node) {
// 停止监听特定目标元素
observer.unobserve(node);
// Observer对象停止监听工作
observer.disconnect()
}
}
}, watch)
}
使用自定义hook
//使用hook
...
import { useObserverHook } from '@/hook/index.js'
...
useObserverHook('#loading', (entries) => {
console.log(entries);
//滚动到底部加载下一页
//entries[0].isIntersecting为true即进入目标元素
if (entries[0].isIntersecting) {
setPage({
...page,
pageNum: page.pageNum + 1
})
}
},null)
useEffect第二个参数
useEffect(()=>{},[])
第二个参数
- 不传参,每次state变动都会触发;
- 参数为空数组,只执行一次,state变动不会触发;
- 参数为数组,并且有依赖项,那么每当依赖项有变动时候会触发;
- null,不监听任何依赖项
更多文章可访问博客