轉載說明:原創不易,未經授權,謝絕任何形式的轉載
使用Intersection Observer API在JavaScript中實作懶加載,無限滾動等功能,而不需要使用複雜的邏輯或導緻性能問題。
Intersection Observer API 用于異步觀察元素與浏覽器視口的交集變化。它使得檢測元素的可見性,或者兩個元素的相對可見性變得容易,而不會使網站變得緩慢并降低使用者體驗。本文将介紹關于Intersection Observer的所有内容。
Intersection Observer 的用途
在我們開始探索Intersection Observer API之前,讓我們看一下在Web應用程式中使用它的一些常見原因:
1、無限滾動
這是一種Web設計技術,使用者向下滾動時不斷加載内容。它消除了手動點選分頁,并可以提高使用者停留時間。
2、懶加載
懶加載是一種設計模式,其中圖檔或其他内容僅在它們被滾動到使用者的視圖中時才加載,以提高性能并節省網絡資源。
3、基于滾動的動畫
這意味着當使用者向上或向下滾動頁面時,會對元素進行動畫處理。有時當達到特定的滾動位置時,動畫會完全播放。其他時候,當滾動位置發生變化時,動畫中的時間也會發生變化。
4、廣告收入計算
我們可以使用Intersection Observer來檢測廣告何時對使用者可見并記錄印象,進而影響廣告收入。
建立 Intersection Observer
讓我們看一下JavaScript中使用Intersection Observer的一個簡單用例。
index.js
const observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
const intersecting = entry.isIntersecting;
entry.target.style.backgroundColor = intersecting ? 'blue' : 'orange';
}
});
const box = document.getElementById('box');
observer.observe(box);
回調函數接收一個數組,其中包含IntersectionObserverEntry接口的對象。該對象包含有關目前被Observer觀察的元素的交叉相關資訊。
每當目标元素與視口相交時,就會調用回調。第一次觀察元素時,也會調用回調。
我們使用for...of循環來疊代傳遞給回調的條目。我們隻觀察一個元素,是以條目數組将隻包含表示框的IntersectionObserverEntry元素,并且for...of循環将隻有一個疊代。
IntersectionObserverEntry元素的isIntersecting屬性傳回一個布爾值,訓示元素是否與視口相交。
當isIntersection為true時,這意味着元素正在從不相交轉換為相交。但是當它為false時,它表示元素正在從相交轉換為不相交。
是以,我們使用isIntersection屬性将元素的顔色設定為藍色,因為它進入視口,并在離開視口時将其設定回黑色。
下面的示例就是上述代碼,box 元素進入視口後顔色的顔色變化:
Intersection Observer 參數屬性
除了回調函數外,IntersectionObserver()構造函數還接受一個選項對象,用于自定義必須滿足的條件以便調用回調函數。
threshold
threshold屬性接受介于0和1之間的值,指定必須在視口中可見的元素的百分比,以便調用回調函數。預設情況下,它的值為0,這意味着當元素的單個像素進入視口時,回調将運作一次。
讓我們修改我們之前的示例,使用100%的門檻值:
index.js
const observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
const intersecting = entry.isIntersecting;
entry.target.style.backgroundColor = intersecting ? 'blue' : 'black';
}
},
// Threshold is 100%
{ threshold: 1 }
);
const box = document.getElementById('box');
observer.observe(box);
現在,隻有在元素的每個像素都可完整見于視口時,改變顔色的回調才會執行。
threshold 還接受多個值,這使得回調在元素通過設定的每個門檻值值時觸發。
例如:index.js
const threshold = document.getElementById('threshold');
const observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
const ratio = entry.intersectionRatio;
threshold.innerText = `${Math.round(ratio * 100)}%`;
}
},
// Multiple treshold values
{ threshold: [0, 0.25, 0.5, 0.75, 1] }
);
const box = document.getElementById('box');
observer.observe(box);
我們将5個百分比值作為數組傳遞給threshold屬性,并将每個值顯示為元素到達它。為此,我們使用intersectionRatio屬性,一個介于0和1之間的數字,表示在視口中的元素的目前百分比。
請注意,所顯示的文本并不總是比對我們的門檻值,例如,示範中的0%門檻值顯示為2%。這是因為當我們快速滾動并到達門檻值時,當回調可以觸發以更新文本時,我們已經滾動更多的元素超過門檻值。
如果我們滾動得更慢,回調就有時間在元素滾過目前門檻值之前更新文本。
rootMargin
rootMargin屬性可以應用于視口或根元素周圍的外邊距。它接受與CSS margin屬性相同的值,例如10px 20px 30px 40px(上、右、下、左)。邊距會增加或縮小 Intersection Observer 觀察目标元素與其交叉的視口區域。
這是使用rootMargin屬性的示例:
const observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
const intersecting = entry.isIntersecting;
entry.target.style.backgroundColor = intersecting ? 'blue' : 'black';
}
},
// Root margin 50px from bottom of viewport
{ rootMargin: '50px' }
);
const box = document.getElementById('box');
observer.observe(box);
設定50px的根邊距後,視口在交叉方面實際上增加了高度,并且當元素距離視口不到50像素時,回調函數将被調用。
示範中的紅線表示觀察者觀察任何交叉的區域的邊界。
我們還可以指定負邊距來縮小用于相交的視口區域。
const observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
const intersecting = entry.isIntersecting;
entry.target.style.backgroundColor = intersecting ? 'blue' : 'black';
}
},
// Negative margin
{ rootMargin: '-50px' }
);
const box = document.getElementById('box');
observer.observe(box);
現在,當元素的一個像素在視口内超過50像素時,回調被觸發。
當元素的一個像素在視口内超過50像素時,它會改變顔色。
root屬性
root屬性接受一個必須是正在觀察的元素的祖先的元素。預設情況下,它為null,這意味着使用視口。你不會經常使用此屬性,但當你在頁面上有一個可滾動的容器并且想要檢查它的某個子元素是否與其相交時,它非常有用。
例如,為了建立本文中的示範,我将root屬性設定為頁面上的可滾動容器,以便您可以輕松地可視化視口和其外部區域,并更好地了解交叉是如何工作的。
第二個回調參數
Intersection Observer() 的回調函數實際上有兩個參數。第一個參數是我們之前讨論過的 entries,第二個參數是正在監聽交叉的 Observer 對象。
const observer = new IntersectionObserver((entries, o) => {
console.log(o === observer); // true
});
在回調函數中,這個參數很有用,可以讓我們在無法通路 Observer 變量的位置使用回調函數,例如在不同的檔案中。
防止記憶體洩漏
為了避免記憶體洩漏和性能問題,我們需要在不再需要觀察元素時停止觀察,例如當它們從 DOM 中删除或在單次基于滾動的動畫後。我們可以使用 unobserve() 方法來實作這一點。
new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
doAnim(entry.target);
observer.unobserve(entry.target);
}
});
});
unobserve() 方法以單個元素作為參數,停止觀察該元素。還有一個 disconnect() 方法,可以使 Observer 停止觀察所有元素。
總結
總之,Intersection Observer 是一個強大的 JavaScript API,可以輕松地檢測元素何時與視口或父元素相交。它讓我們能夠實作惰性加載、基于滾動的動畫、無限滾動等功能,而不會引起性能問題和複雜的邏輯。
今天先分享到這裡,希望今天的分享對你有所幫助,在你的開發中,别忘記嘗試下這個Intersection Observer API。感謝你的閱讀,如果你喜歡我的分享,别忘了點贊轉發,讓更多的人看到,最後别忘記關注「前端達人」,你的支援将是我分享最大的動力,後續我會持續輸出更多内容,敬請期待。
https://javascript.plainenglish.io/javascript-intersection-observer-cded4e80a377
非直接翻譯,有自行改編和添加部分,翻譯水準有限,難免有疏漏,歡迎指正