簡介
1 .觀察元素是否在可見區(qū)域
2 .使用場景:
1 .圖片懶加載-當(dāng)圖片滾動到可見位置的時候才加載
2 .內(nèi)容無限滾動-用戶滾動到接近內(nèi)容底部時直接加載更多
3 .檢測廣告的曝光率,廣告是否被看到了
4 .用戶看到某個區(qū)域時執(zhí)行任務(wù)或播放動畫
3 .傳統(tǒng)實現(xiàn):監(jiān)聽scroll事件,調(diào)用目標元素的getBoundingClientRect().得到相對于視口左上角的坐標,在判斷是否在視口之內(nèi).但是觸發(fā)非常頻繁,這樣計算就會有性能問題
4 .最簡單例子
import React,{useRef} from 'react'
import {useInViewport} from 'ahooks'
export default function Drag(props){
const ref=useRef()
const [inViewport,ratio]=useInViewport(ref,{
threshold:0.1,
})
console.log(inViewport,ratio)
return (
<div>
<div style={{ width: 300, height: 300, overflow: 'scroll', border: '1px solid',position:'absolute',top:'100px' }}>
scroll here
<div style={{ height: 800 }}>
<div
ref={ref}
style={{
border: '1px solid',
height: 100,
width: 100,
textAlign: 'center',
marginTop: 80,
}}
>
observer dom
</div>
</div>
</div>
{/* <div style={{ marginTop: 16, color: inViewport ? '#87d068' : '#f50' }}>
inViewport: {inViewport ? 'visible' : 'hidden'}
</div> */}
</div>
)
}
原生實現(xiàn)
1 .IntersectionObserver的實現(xiàn)屑咳,應(yīng)該采用requestIdleCallback()虚汛,即只有線程空閑下來侦厚,才會執(zhí)行觀察器大脉。這意味著浸卦,這個觀察器的優(yōu)先級非常低,只在其他任務(wù)執(zhí)行完颁褂,瀏覽器有了空閑才會執(zhí)行
import React,{useEffect,useState} from 'react'
export default function Drag(props){
const [url,setUrl]=useState('222')
useEffect(()=>{
const io=new IntersectionObserver((entries)=>{
entries.forEach((change)=>{
// let [container,visible]=change
// 這樣操作還不行
if(change.intersectionRatio<=0)return
// 消失
let container=change.target
let visible=change.isVisible
console.log('被觀察的目標出現(xiàn)在了視口里面')
// 可以加載更多的數(shù)據(jù),實現(xiàn)無限滾動的操作.這樣做的虛擬列表,我們連右邊的滾動條也可以自己實現(xiàn),不用瀏覽器自帶的版本,虛擬列表也可以這么做.因為瀏覽器的長度列表是完全靠高度撐起來的,最高是3千萬的px.有點離譜.感覺創(chuàng)建這么高的div應(yīng)該也會耗時間吧.
// 可以更換圖片
// 注意這里是每次出現(xiàn)都觸發(fā),但其實我們應(yīng)該是這個機制只觸發(fā)一次
})
},{})
io.observe(document.getElementById('target'),{
threshold:[0.5,1],
// 只有出現(xiàn)的時候才觸發(fā)函數(shù),也就是目標元素出現(xiàn)了0.5的時候就會觸發(fā)函數(shù)u
root:document.getElementById('parent'),
// 觸發(fā)檢測的根元素
})
},[])
return (
<div>
<div style={{ width: 300, height: 300, overflow: 'scroll', border: '1px solid',position:'absolute',top:'100px'}}
id="parent"
>
<div style={{ height: 800 }}>
這是一個很長的占位操作
</div>
<div
style={{
border: '1px solid',
height: 100,
width: 100,
textAlign: 'center',
marginTop: 80,
}}
id='target'
>
observer dom{url}
</div>
</div>
{/* <div style={{ marginTop: 16, color: inViewport ? '#87d068' : '#f50' }}>
inViewport: {inViewport ? 'visible' : 'hidden'}
</div> */}
</div>
)
}
圖片懶加載的實現(xiàn)效果
1 .img不是先來默認圖片故黑,而是一開始都沒有地址
img{visibility:hidden}
img[src]{
visibility:visible
}
<img />
2 .注意這是沒有src="",有的瀏覽器空值都會發(fā)出請求