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