概念
IntersectionObserver接口(從屬于Intersection Observer API)為開發(fā)者提供了一種可以異步監(jiān)聽目標(biāo)元素與其祖先或視窗(viewport)交叉狀態(tài)的手段蛤育。祖先元素與視窗(viewport)被稱為根(root)揪阶。
這是MDN上給的官方概念挫酿,不用去管它奢讨,我粘出來只是為了顯得專業(yè)點(diǎn)嘛...
重點(diǎn)看這里監(jiān)聽目標(biāo)元素與其祖先或視窗交叉狀態(tài)的手段靠闭,其實(shí)就是觀察一個(gè)元素是否在視窗可見斗埂。
可以看到,交叉了就是說明當(dāng)前元素在視窗里叠洗,當(dāng)前就是可見的了甘改。
API
var io = new IntersectionObserver(callback, options)
其實(shí)就是一個(gè)簡(jiǎn)單的構(gòu)造函數(shù)。
以上代碼會(huì)返回一個(gè)IntersectionObserver
實(shí)例灭抑,callback
是當(dāng)元素的可見性變化時(shí)候的回調(diào)函數(shù)十艾,options
是一些配置項(xiàng)(可選)。
我們使用返回的這個(gè)實(shí)例來進(jìn)行一些操作腾节。
io.observe(document.querySelector('img')) 開始觀察忘嫉,接受一個(gè)DOM節(jié)點(diǎn)對(duì)象
io.unobserve(element) 停止觀察 接受一個(gè)element元素
io.disconnect() 關(guān)閉觀察器
options
root
用于觀察的根元素荤牍,默認(rèn)是瀏覽器的視口,也可以指定具體元素榄融,指定元素的時(shí)候用于觀察的元素必須是指定元素的子元素
threshold
用來指定交叉比例参淫,決定什么時(shí)候觸發(fā)回調(diào)函數(shù)救湖,是一個(gè)數(shù)組愧杯,默認(rèn)是[0]
。
const options = {
root: null,
threshold: [0, 0.5, 1]
}
var io = new IntersectionObserver(callback, options)
io.observe(document.querySelector('img'))
上面代碼鞋既,我們指定了交叉比例為0力九,0.5,1邑闺,當(dāng)觀察元素img0%跌前、50%、100%時(shí)候就會(huì)觸發(fā)回調(diào)函數(shù)
rootMargin
用來擴(kuò)大或者縮小視窗的的大小陡舅,使用css的定義方法抵乓,10px 10px 30px 20px
表示top、right靶衍、bottom 和 left的值
const options = {
root: document.querySelector('.box'),
threshold: [0, 0.5, 1],
rootMargin: '30px 100px 20px'
}
為了方便理解灾炭,我畫了張圖,如下
首先我們來看下圖上的問題颅眶,藍(lán)線是什么呢蜈出?他就是咱們定義的root元素,我們添加了rootMargin
屬性涛酗,將視窗的增大了铡原,虛線就是現(xiàn)在的視窗,所以元素現(xiàn)在也就在視窗里面了商叹。
由此可見燕刻,root元素只有在rootMargin
為空的時(shí)候才是絕對(duì)的視窗。
說了簡(jiǎn)單的options剖笙,接下來我們看下callback
卵洗。
callback
上面我們說到,當(dāng)元素的可見性變化時(shí)枯途,就會(huì)觸發(fā)callback函數(shù)忌怎。
callback函數(shù)會(huì)觸發(fā)兩次,元素進(jìn)入視窗(開始可見時(shí))和元素離開視窗(開始不可見時(shí))都會(huì)觸發(fā)
var io = new IntersectionObserver((entries)=>{
console.log(entries)
})
io.observe($0)
以上代碼酪夷,請(qǐng)?jiān)赾hrome控制臺(tái)進(jìn)行調(diào)試榴啸,這里我使用了$0
選擇了上一次我審查元素的選擇的節(jié)點(diǎn)
運(yùn)行結(jié)果如下
我們可以看到callback函數(shù)有個(gè)entries
參數(shù),它是個(gè)IntersectionObserverEntry
對(duì)象數(shù)組晚岭,接下來我們重點(diǎn)說下IntersectionObserverEntry對(duì)象
IntersectionObserverEntry
IntersectionObserverEntry
提供觀察元素的信息鸥印,有七個(gè)屬性。
boundingClientRect 目標(biāo)元素的矩形信息
intersectionRatio 相交區(qū)域和目標(biāo)元素的比例值 intersectionRect/boundingClientRect 不可見時(shí)小于等于0
intersectionRect 目標(biāo)元素和視窗(根)相交的矩形信息 可以稱為相交區(qū)域
isIntersecting 目標(biāo)元素當(dāng)前是否可見 Boolean值 可見為true
rootBounds 根元素的矩形信息,沒有指定根元素就是當(dāng)前視窗的矩形信息
target 觀察的目標(biāo)元素
time 返回一個(gè)記錄從IntersectionObserver
的時(shí)間到交叉被觸發(fā)的時(shí)間的時(shí)間戳
上面幾個(gè)矩形信息的關(guān)系如下
?? 劃重點(diǎn)
intersectionRatio和isIntersecting是用來判斷元素是否可見的库说,押題咯...
懶加載
好了狂鞋,通過上面一些概念我們大概了解了IntersectionObserver
是個(gè)什么東西,接下來我們用它來寫點(diǎn)代碼潜的,寫什么呢骚揍?沒錯(cuò)就是懶加載。
通過IntersectionObserver來實(shí)現(xiàn)懶加載啰挪,就簡(jiǎn)單的多了信不,我們只需要設(shè)置回調(diào),判斷當(dāng)前元素是否可見亡呵,再進(jìn)行渲染操作就行了抽活,而不用去關(guān)心內(nèi)部的計(jì)算。
主要代碼如下
const io = new IntersectionObserver(()=>{ // 實(shí)例化 默認(rèn)基于當(dāng)前視窗
})
let ings = document.querySelectorAll('[data-src]') // 將圖片的真實(shí)url設(shè)置為data-src src屬性為占位圖 元素可見時(shí)候替換src
function callback(entries){
entries.forEach((item) => { // 遍歷entries數(shù)組
if(item.isIntersecting){ // 當(dāng)前元素可見
item.target.src = item.target.dataset.src // 替換src
io.unobserve(item.target) // 停止觀察當(dāng)前元素 避免不可見時(shí)候再次調(diào)用callback函數(shù)
}
})
}
imgs.forEach((item)=>{ // io.observe接受一個(gè)DOM元素锰什,添加多個(gè)監(jiān)聽 使用forEach
io.observe(item)
})
本想錄制個(gè)GIF圖下硕,使用Recordlt始終上傳不了,誰有好用的GIF圖錄制軟件請(qǐng)推薦個(gè)汁胆,不勝感激梭姓。。
吶沦泌,給你花??
因篇幅有限糊昙,完整代碼請(qǐng)戳github ??
??注意
目前IntersectionObserver是一個(gè)實(shí)驗(yàn)中的功能,請(qǐng)酌情使用谢谦。