IntersectionObserver
callback
var observer = new IntersectionObserver(callback,options);
callback 監聽元素的可見性
options 配置參數
callback
一般會觸發兩次,一次是目標進入視口(可見),另一次是完全離開(不可見)
let observer = new IntersectionObserver(changes => {
changes.forEach(change => {
// 完全可見時為1,完全不可見時小於等於0
console.log(change.intersectionRatio);
// 被觀察的目標元素,是一個 DOM 節點對象
// 當前可視區域正在變化的元素
console.log(change.target);
})
})
如果沒設置Option 就只觸發兩次
每一個屬性的含義
time:可見性發生變化的時間,是一個高精度時間戳,單位為毫秒
target:被觀察的目標元素,是一個 DOM 節點對象
rootBounds:根元素的矩形區域的信息,getBoundingClientRect()方法的返回值,如果沒有根元素(即直接相對於視口滾動),則返回null
boundingClientRect:目標元素的矩形區域的信息
intersectionRect:目標元素與視口(或根元素)的交叉區域的信息
intersectionRatio:目標元素的可見比例,即intersectionRect占boundingClientRect的比例,完全可見時為1,完全不可見時小於等於0
time: 3893.92 🔽rootBounds: ClientRect bottom: 920 height: 1024 left: 0 right: 1024 top: 0 width: 920
option
threshold 屬性
threshold 屬性決定了什么時候觸發回調函數
new IntersectionObserver( entries => {/* ... */}, { threshold: [0, 0.25, 0.5, 0.75, 1] } );
比如,[0, 0.25, 0.5, 0.75, 1]就表示當目標元素 0%、25%、50%、75%、100% 可見時,會觸發回調函數。
root屬性 rootMargin屬性
root屬性指定目標的容器節點(根元素)
屬性 | 說明 |
---|---|
root | 監聽元素的祖先元素 Element 對象 |
rootMargin | 一個在計算交叉值時添加至根的邊界盒(bounding_box)中的一組偏移量,類型為字符串,可以有效的縮小或擴大根的判定范圍從而滿足計算需要。語法大致和 CSS 中的 margin 屬性等同,默認值是"0px 0px 0px 0px" top、right、bottom 和 left單位: “ px ”,”% |
threshold | 規定了一個監聽目標與邊界盒交叉區域的比例值,可以是一個具體的數值或是一組 0.0 到 1.0 之間的數組。若指定值為 0.0,則意味着監聽元素即使與根有 1 像素交叉,此元素也會被視為可見. |
{
root: Element,
rootMargin: string,
threshold: number | number[]
}
默認
{
root: null,
rootMargin: "0px 0px 0px 0px",
threshold: [0]
}
使用
方法 | 說明 |
---|---|
disconnect() | 使 IntersectionObserver 對象停止監聽工作。 |
observe() | 使 IntersectionObserver 開始監聽一個目標元素。 |
unobserve() | 使 IntersectionObserver 停止監聽特定目標元素。 |
IntersectionObserver
使用的是異步的方式,可以不用擔心性能問題
- 開始觀察某個獵物:
observer.observe(el)
- 取消觀察某個獵物:
observer.unobserve(el)
- 自爆,關掉這個觀察器:
observer.disconnect()
可見性demo
const target = document.getElementById('target')
const observer = new IntersectionObserver((entries) => {
const [entry] = entries
if (entry.isIntersecting) {
console.log('元素曝光了')
}
})
observer.observe(target)
懶加載
為了惰性加載圖片,當然不能把 img 的 src 直接設置成圖片地址,不然瀏覽器直接就顯示了。而一般是放在
data-src
屬性中,或增加lazy-load
類。<img data-src="https://example.com/me.png" width="100px" height="50px" /> 找到所有需要惰性加載的圖片 var images = document.querySelectorAll('img[data-src]'); var observer = new IntersectionObserver(onIntersection); images.forEach(img => { observer.observe(img); });
const target = document.getElementById('ccc')
const observer = new IntersectionObserver((entries) => {
const [entry] = entries
if (entry.isIntersecting) {
entry.target.src='xxxx';
// 取消監控
observer.unobserve(entry.target)
}
})
observer.observe(target)
當獵物進入到鏡頭后,isIntersecting會是true,不在鏡頭內就是false。
解釋
- intersectionRatio 相交比例。剛開始相交是0%,相交一半是50%,完全進入則是100%
- isIntersecting 是否正在相交。
intersectionRatio != 0
即正在相交。(后來增加的屬性) - target 被觀察的元素。
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if(entry.isIntersecting) {
console.log("元素相交");
} else {
console.log("元素不相交");
}
});
});
root 的理解
<div style="height:400px;overflow-y:scroll">
<div style="height:200vh;background-color: khaki;"></div>
<div id="ccc" style="height:500px;background-color: #b1ff6d;"></div>
<div style="height:200vh;background-color: khaki;"></div>
</div>
const target = document.getElementById('ccc')
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log("元素相交");
} else {
console.log("元素不相交");
}
});
}, {
root: document.querySelector('#aaa'),
});
observer.observe(target)
rootMargin
<div style="height:200vh;background-color: #f00d0d;"></div>
<div style="height:400px;overflow-y:scroll;" class="aaa">
<div id="ccc" style="height:500px;background-color: #b1ff6d;"></div>
<div style="height:200vh;background-color: khaki;"></div>
</div>
const target = document.getElementById('ccc')
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log("元素相交");
} else {
console.log("元素不相交");
}
});
}, {
root: document.querySelector('#aaa'),
rootMargin:'50%' //根 400px 50% 是200px
/* 距離下面200px的時候相交*/
/* 距離下面200px的時候不相交*/
});
observer.observe(target)