IntersectionObserver (交叉觀察器)
IntersectionObserver
提供了一種異步觀察目标元素與其祖先元素或頂級文檔視窗(viewport)交叉狀态的方法。祖先元素與視窗(viewport)被稱為根(root)。
IntersectionObserver
對象被建立以後,其被配置為監聽根中一段給定比例的可見區域。一旦IntersectionObserver被建立,則無法更改其配置,是以一個給定的觀察者對象隻能用來監聽可見區域的特定變化值;可以在同一個觀察者對象中配置監聽多個目标元素。
var obj = new IntersectionObserver(callback, options);
// 開始監聽 element為單個dom元素,多個元素都需要監聽 需要多次調用 同一個觀察者對象中配置監聽多個目标元素。
obj.observe(element);
// 停止監聽
obj.unobserve(element);
// 銷毀監聽
obj.disconnect();
// 傳回所有觀察目标的對象數組 每個對象包含目标元素與根每次的相交資訊。
callback回調函數中,參數是每一個監聽的對象
var obj = new IntersectionObserver(changes => {
//changes是一個數組,數組中每個元素都是監聽的對象,每個對象包含很多資訊,提取出需要的進行判斷
changes.forEach(item => {
let {
isIntersecting,
target
} = item;
if (isIntersecting) {
lazyImgView(target);
//滿足條件後 停止監聽
obj.unobserve(target);
}
})
}, options);
每個對象包含8個屬性
time:可見性發生變化的時間,是一個高精度時間戳,機關為毫秒
target:被觀察的目标元素,是一個 DOM 節點對象
rootBounds:根元素的矩形區域的資訊,getBoundingClientRect()方法的傳回值,如果沒有根元素(即直接相對于視口滾動),則傳回null
boundingClientRect:目标元素的矩形區域的資訊
intersectionRect:目标元素與視口(或根元素)的交叉區域的資訊
intersectionRatio:目标元素的可見比例,即intersectionRect占boundingClientRect的比例,完全可見時為1,完全不可見時小于等于0
isIntersecting是用來判斷元素是否符合options中的可見條件
例如:
var options = {
threshold: [0.7]
}
var obj = new IntersectionObserver(changes => {
changes.forEach(item => {
console.log(item)
let {
isIntersecting,
target
} = item;
//target 出現70%,isIntersecting為true
if (isIntersecting) {
lazyImgView(target);
obj.unobserve(target);
}
})
}, options);
接着看一下options
這個 options 配置對象,有三個屬性 threshold,root,rootMargin
threshold,他是一個數組
: [0, 0.25, 0.5, 0.75, 1]
這個表示目标元素 0%、25%、50%、75%、100% 可見時,會觸發回調函數
root,
監聽元素的祖先元素
Element
對象,其邊界盒将被視作視口。
目标在根的可見區域的的任何不可見部分都會被視為不可見。
rootMargin.
一個在計算交叉值時添加至根的邊界盒中的一組偏移量
可以有效的縮小或擴大根的判定範圍進而滿足計算需要。文法大緻和CSS 中的
margin
屬性等同,預設值是"0px 0px 0px 0px" (字元串) 該屬性還沒有正式使用
在交叉檢測開始之前,由
rootMargin規定的矩形的每一邊都會被添加至
root
元素的邊框盒的相應邊。例如,可以讓你向外調整邊界,使得目标元素被認為是100%可見的,即使此元素得一部分長或寬被裁剪,或者在邊緣過于靠近根邊框盒邊界的情況下,将目标視為部分隐藏。
相關介紹
浏覽器相容:
html:
效果:
(為了能夠清晰的分辨 加載更多的出現,每次請求的資料和新資料之間有一個空,是以能夠看到有一個空缺)
完整代碼:
var imgListMoudule = (function () {
// 擷取操作得dom元素
var container = $('#imgList'),
page = 1,
supportNumber = 0;
// 擷取資料 分頁加載
var queryData = (page) => {
//假資料
data = [{
imgurl: "img/img.png",
id: "1"
}, {
imgurl: "img/img.png",
id: "2"
}, {
imgurl: "img/img.png",
id: "3"
}, {
imgurl: "img/img.png",
id: "4"
}, {
imgurl: "img/img.png",
id: "5"
}, {
imgurl: "img/img.png",
id: "6"
}, {
imgurl: "img/img.png",
id: "7"
}, {
imgurl: "img/img.png",
id: "8"
}, {
imgurl: "img/img.png",
id: "9"
}]
bindHtml(data);
// $.ajax({
// type: "POST",
// url: "",
// data: "",
// async: true,
// success: function (data) {
// data = [{
// imgurl: "",
// id: "1"
// }]
if (page > 3) {
// 資料沒有了 将加載更多的元素去掉 不會再觸發加載更多
$('.load_more').hide();
}
bindHtml(data);
++page;
// },
// error: function () {
// console.log("送出失敗!");
// }
// });
}
// 頁面渲染
var bindHtml = data => {
var result = [];
for (var i = 0; i < data.length; i += 2) {
result.push(data.slice(i, i + 2));
}
var str = "";
result.forEach(itemArray => {
str += ` <div class="img_list_box" lazyload>`;
itemArray.forEach(item => {
str += `<a href="javascript:void(0)" class="img_item" data-id="${item.id}">
<div class="img_box" data-id="${item.id}">
<img src="" alt="" class="index_img" data-realUrl="${item.imgurl}">
</div>
<div class="img_text">
<div class="look_box img_text_item">
<span>111</span>
<img src="img/look_icon.png" alt="">
</div>
<div class="zan_box img_text_item">
<span>111</span>
<img src="img/zan_icon.png" alt="" class="zan_btn">
</div>
</div>
</a>`;
})
str += ` </div>`;
})
container.append(str);
}
// 懶加載監聽
var lazyLoad = () => {
var options = {
threshold: [0.7]
}
var obj = new IntersectionObserver(changes => {
changes.forEach(item => {
let {
isIntersecting,
target
} = item;
if (isIntersecting) {
lazyImgView(target);
obj.unobserve(target);
}
})
}, options);
// 擷取需要懶加載的元素 隻擷取設定了lazyload屬性得元素
var imgBox = $('.img_list_box[lazyload]');
[].forEach.call(imgBox, lazyImg => {
obj.observe(lazyImg);
})
}
// 懶加載渲染
var lazyImgView = item => {
var imgs = $(item).find('.img_box img');
// 防止之前資料重新渲染,移除掉已經監聽得
item.removeAttribute('lazyload');
[].forEach.call(imgs, img => {
img.src = img.getAttribute('data-realUrl');
img.onload = () => {
img.style.opacity = 1;
}
})
}
// 加載更多
var loadMore = () => {
var options = {
threshold: [0.5]
}
var loadMoreDom = document.getElementsByClassName('load_more')[0];
if (!loadMoreDom) {
return false;
}
var obj = new IntersectionObserver(changes => {
if (changes[0].isIntersecting) {
queryData(page);
lazyLoad();
}
}, options);
obj.observe(loadMoreDom);
}
return {
async init() {
queryData(page);
lazyLoad();
loadMore();
}
}
})();
imgListMoudule.init();
參考
IntersectionObserver API 使用教程
intersectionObserver WebApiI