原生實現img-lazyLoad:圖片延遲載入(基於intersection Observer)
intersection Observer簡介
這個api是用來檢測dom元素交集的,常見的應用場景之一就是本文提到的對圖片進行懶載入,即:拖動視窗滾動條,到達當前這個圖片的時候,再去讀取掛在自定義屬性(比如:'data-src')上的url地址,之後將該url地址寫到到src屬性上去進行下載、展示這個圖片。因此,我們關注的重點是:該圖片是否滾動到了當前視窗的可視區域。通常解決的辦法是,監聽視窗元素的scroll事件,在事件處理程式中對圖片的位置做判斷。然而,這麼做的一個弊端是,因為js是單執行緒的,而scroll事件出現的又很密集,每次都去響應scroll事件可能會影響使用者體驗。
intersection Observer的誕生就是為了處理這種類似於上文提到的元素交集檢測。它會觀察我們的目標元素 ,當目標元素 出現在root元素 的可視區域時便會觸發一個(我們事先放進去的)回撥函式,於是我們可以在回撥函式裡面處理業務邏輯。
這裡出現了兩個小概念,對應於本文實現的圖片懶載入功能來說:
- 目標元素:指的就是那些我們需要懶載入的圖片
- root元素指的就是目標元素的父視窗,比如這裡的圖片的父元素容器
利用intersection Observer實現懶載入
檢視該案例:
- 在index.html頁面內有一個scrollContainer,在裡面首先是放了幾段文字,之後是5個img元素,並將img的url地址寫在了自定義屬性'data-src'內。
- 在css檔案內定義了一些樣式,其中,move-in是在我們對圖片真正進行載入時才會新增的動畫效果。
現在,無論我們怎麼拖動滾動條都無法看見圖片,因為我們僅僅是把img的url寫在了自定義屬性中而不是src屬性中。接下來,我們需要利用intersection Observer對這些暫時看不見的圖片元素進行觀察,當確認他們滾動到了窗體的可視區域時,我們在回撥函式中對其進行載入。
建立一個observer:
const observer = new IntersectionObserver(callback,option)
option配置root元素和回撥函式觸發機制,這裡我們將scrollContainer這個div設為root。
callback就是當檢測到目標元素與root元素交集時會呼叫的函式,形如:
(entrances, observer)=>{ // entrances是個陣列物件,包含了所有的目標元素,通常我們會遍歷它們,並判斷每一個單獨的個體是否與root元素產生了交集,如果是,那麼我們就會執行一些邏輯 }
連線目標元素
剛才我們建立了observer,並且設定了它的root元素,現在需要告訴這個observer,我們需要觀察哪些目標元素與此root元素的交集。
通過observer.observe(target)
進行連結
最終的程式碼
const imgs = document.querySelectorAll('img') //獲取所有待觀察的目標元素 var options = { root: document.querySelector('.scrollContainer'), rootMargin: '0px', threshold: 1.0 } function lazyLoad(target) { const observer = new IntersectionObserver((entrances, observer) => { entrances.forEach(entrance => { if (entrance.isIntersecting) { const img = entrance.target; const src = img.getAttribute('data-src'); img.setAttribute('src', src) img.classList.add('move-in') observer.disconnect() } }) }, options); observer.observe(target) } imgs.forEach(lazyLoad)