最近再查看 react 的 useEffect文档时,看到有个示例:定制 useIntersectionObserver Hook。
通过了IntersectionObserver 方式实现了,可以异步观察目标元素与顶级文档或者根元素交叉状态的方法。那么是不是可以通过该方法代 scroll 事件呢,于是就查看了文档做了个例子。
IntersectionObserver 属性
root: 边界的元素或者文档,默认是顶级文档
rootMarin: 计算交叉时边角盒的偏移量,支持%、px, 默认'0px 0px 0px 0px'
thresholds: 一个包含阈值的列表,按升序排列,列表中的每个阈值都是监听对象的交叉区域与边界区域的比率。当监听对象的任何阈值被越过时,都会生成一个通知(Notification)。如果构造器未传入值,则默认值为 0。
IntersectionObserver 实例
observe(): 监听的目标元素
disconnect(): 停止监听目标
使用示例:
const intersectionObserver = new IntersectionObserver((entries) => {
// 如果 intersectionRatio 为 0,则目标在视野外,
// 我们不需要做任何事情。
if (entries[0].intersectionRatio <= 0) return;
loadItems(10);
console.log("Loaded new items");
});
// 开始监听
intersectionObserver.observe(document.querySelector(".scrollerFooter"));
参考mdn web docs:developer.mozilla.org/zh-CN/docs/…
IntersectionObserver 示例
useIntersectionObserver hook
import { useEffect, useState } from "react"
const useIntersectionObserver = (ref: any, options?: object) => {
const [isIntersecting, setIsIntersecting] = useState<boolean>(false)
useEffect(() => {
const elm = ref.current
const intersectionObserver = new IntersectionObserver((entries) => {
setIsIntersecting(entries[0].isIntersecting)
// 开始监听
}, options)
intersectionObserver.observe(elm)
return () => {
intersectionObserver.disconnect()
}
}, [ref])
return isIntersecting
}
export default useIntersectionObserver
useIntersectionObserver 应用
import { useRef } from "react"
import useIntersectionObserver from '@/hooks/useIntersectionObserver'
const Rolling = () => {
const redRef = useRef<HTMLDivElement>(null)
const parentRef = useRef<HTMLDivElement>(null)
const isIntersection = useIntersectionObserver(redRef, { root: parentRef.current, rootMargin: '50px 0px 0px 0px' })
return (
<div ref={parentRef} className="rolling-box" style={{ height: 'calc(100vh - 310px)', overflow: 'hideen', position: 'relative' }}>
{ !isIntersection && <div style={{ position: 'absolute', left: '45%', top: '10px', zIndex: 2 }} >这是 <span style={{ color: 'blue' }}> red hidden </span></div> }
<div className="rolling-box" style={{ height: '100%', overflow: 'auto', padding: '50px 0' }}>
<div style={{height: '500px', border: '1px solid #eee',}}></div>
<div ref={redRef} style={{height: '300px', border: '1px solid red', margin: '50px 0 0 0'}}>red</div>
<div style={{height: '500px', border: '1px solid #eee', margin: '50px 0 0 0'}}></div>
<div style={{height: '300px', border: '1px solid blue', margin: '50px 0 0 0'}}>blue</div>
<div style={{height: '500px', border: '1px solid #eee', margin: '50px 0 0 0'}}></div>
<div style={{height: '500px', border: '1px solid #eee', margin: '50px 0 0 0'}}></div>
<div style={{height: '500px', border: '1px solid #eee', margin: '50px 0 0 0'}}></div>
<div style={{height: '500px', border: '1px solid #eee', margin: '50px 0 0 0'}}></div>
<div style={{height: '500px', border: '1px solid #eee', margin: '50px 0 0 0'}}></div>
</div>
</div>
)
}
export default Rolling
red box 在指定视窗内:
red box 不在指定视窗内: