概念
IntersectionObserver介面(從屬於Intersection Observer API)為開發者提供了一種可以非同步監聽目標元素與其祖先或視窗(viewport)交叉狀態的手段。祖先元素與視窗(viewport)被稱為根(root)。
這是MDN上給的官方概念,不用去管它,我粘出來只是為了顯得專業點嘛...
重點看這裡監聽目標元素與其祖先或視窗交叉狀態的手段,其實就是觀察一個元素是否在視窗可見。
可以看到,交叉了就是說明當前元素在視窗裡,當前就是可見的了。
API
var io = new IntersectionObserver(callback, options)
複製程式碼
其實就是一個簡單的建構函式。
以上程式碼會返回一個IntersectionObserver
例項,callback
是當元素的可見性變化時候的回撥函式,options
是一些配置項(可選)。
我們使用返回的這個例項來進行一些操作。
io.observe(document.querySelector('img')) 開始觀察,接受一個DOM節點物件
io.unobserve(element) 停止觀察 接受一個element元素
io.disconnect() 關閉觀察器
複製程式碼
options
root
用於觀察的根元素,預設是瀏覽器的視口,也可以指定具體元素,指定元素的時候用於觀察的元素必須是指定元素的子元素
threshold
用來指定交叉比例,決定什麼時候觸發回撥函式,是一個陣列,預設是[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,當觀察元素img0%、50%、100%時候就會觸發回撥函式
rootMargin
用來擴大或者縮小視窗的的大小,使用css的定義方法,10px 10px 30px 20px
表示top、right、bottom 和 left的值
const options = {
root: document.querySelector('.box'),
threshold: [0, 0.5, 1],
rootMargin: '30px 100px 20px'
}
複製程式碼
為了方便理解,我畫了張圖,如下
首先我們來看下圖上的問題,藍線是什麼呢?他就是我們們定義的root元素,我們新增了rootMargin
屬性,將視窗的增大了,虛線就是現在的視窗,所以元素現在也就在視窗裡面了。
由此可見,root元素只有在rootMargin
為空的時候才是絕對的視窗。
說了簡單的options,接下來我們看下callback
。
callback
上面我們說到,當元素的可見性變化時,就會觸發callback函式。
callback函式會觸發兩次,元素進入視窗(開始可見時)和元素離開視窗(開始不可見時)都會觸發
var io = new IntersectionObserver((entries)=>{
console.log(entries)
})
io.observe($0)
複製程式碼
以上程式碼,請在chrome控制檯進行除錯,這裡我使用了$0
選擇了上一次我審查元素的選擇的節點
執行結果如下
我們可以看到callback函式有個entries
引數,它是個IntersectionObserverEntry
物件陣列,接下來我們重點說下IntersectionObserverEntry物件
IntersectionObserverEntry
IntersectionObserverEntry
提供觀察元素的資訊,有七個屬性。
boundingClientRect 目標元素的矩形資訊
intersectionRatio 相交區域和目標元素的比例值 intersectionRect/boundingClientRect 不可見時小於等於0
intersectionRect 目標元素和視窗(根)相交的矩形資訊 可以稱為相交區域
isIntersecting 目標元素當前是否可見 Boolean值 可見為true
rootBounds 根元素的矩形資訊,沒有指定根元素就是當前視窗的矩形資訊
target 觀察的目標元素
time 返回一個記錄從
IntersectionObserver
的時間到交叉被觸發的時間的時間戳
上面幾個矩形資訊的關係如下
? 劃重點
intersectionRatio和isIntersecting是用來判斷元素是否可見的,押題咯...
懶載入
好了,通過上面一些概念我們大概瞭解了IntersectionObserver
是個什麼東西,接下來我們用它來寫點程式碼,寫什麼呢?沒錯就是懶載入。
通過IntersectionObserver來實現懶載入,就簡單的多了,我們只需要設定回撥,判斷當前元素是否可見,再進行渲染操作就行了,而不用去關心內部的計算。
主要程式碼如下
const io = new IntersectionObserver(()=>{ // 例項化 預設基於當前視窗
})
let ings = document.querySelectorAll('[data-src]') // 將圖片的真實url設定為data-src src屬性為佔點陣圖 元素可見時候替換src
function callback(entries){
entries.forEach((item) => { // 遍歷entries陣列
if(item.isIntersecting){ // 當前元素可見
item.target.src = item.target.dataset.src // 替換src
io.unobserve(item.target) // 停止觀察當前元素 避免不可見時候再次呼叫callback函式
}
})
}
imgs.forEach((item)=>{ // io.observe接受一個DOM元素,新增多個監聽 使用forEach
io.observe(item)
})
複製程式碼
本想錄制個GIF圖,使用Recordlt始終上傳不了,誰有好用的GIF圖錄制軟體請推薦個,不勝感激。。
吶,給你花?
因篇幅有限,完整程式碼請戳github ?
⚠️注意
目前IntersectionObserver是一個實驗中的功能,請酌情使用。