问题
今天在开发组件库的过程中涉及到了图片懒加载,自己查询后也实现了功能
引用
需要先了解一个api
IntersectionObserver
它可以监听一个元素是否与另一个元素出现交集(接触),体现在图片懒加载中就是目标图片是否将接触展示元素
- 实例化
let imgObserver = new IntersectionObserver(()=>{});
// imgObserver 属性
// observer() 给目标元素添加监视
// unobserve() 停止监听元素
// takeRecords() 返回所有监视的元素数组
// disconnect() 停止监听所有元素
通过new的方式可以创建一个空的监视器(imgServer)
- 对元素创建监视
// 获取监视的目标元素 --- 这里监视图片组
let imgs = document
let imgObserver = new IntersectionObserver(callback, options);
// 循环给每个图片添加监视
imgs.forEach(item => {
imgObserver.observer(item)
})
实例时接受一个回调函数,函数接受一个参数 ,此回调函数在监视元素位置改变时触发
- callback 回调函数
let imgObserver = new IntersectionObserver((entries)=>{
// entries 保存了监视的元素组(数组)
// 每个 元素都有一下几个属性
// target: 监视的目标元素
// isIntersecting : 当监视元素出现在可视区域则值为true, 监视元素离开可视区则值为false
// time: 返回一个记录从 IntersectionObserver 的时间原点到交叉被触发的时间的时间戳
// intersectionRect: 用来描述root和目标元素的相交区域
// intersectionRatio: 返回目标元素出现在可视区的比例
// boundingClientRect: 返回包含目标元素的边界信息,返回结果与element.getBoundingClientRect() 相同
// rootBounds: 用来描述交叉区域观察者(intersection observer)中的根.
}, options);
- 对每一个元素进行处理
let imgObserver = new IntersectionObserver((entries)=>{
entries.forEach(item => {
// 当监视元素出现可视区
if(item.isIntersecting){
// 处理 --- 具体到懒加载就是 替换src
item.target.src = item.target.dataset.src;
// 完成后 取消当前监视元素的监视
imgObserver.unobserver(item.target)
}
})
}
- options
let imgObserver = new IntersectionObserver((entries, {
root: // 监视的根元素, 即可视元素, 默认为html元素
rootMargin: // 计算交叉时添加到**根(root)**边界盒[bounding box](https://link.juejin.cn/?target=https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FGlossary%2Fbounding_box "https://developer.mozilla.org/en-US/docs/Glossary/bounding_box")的矩形偏移量, 可以有效的缩小或扩大根的判定范围从而满足计算需要。所有的偏移量均可用**像素**(`px`)或**百分比**(`%`)来表达, 默认值为"0px 0px 0px 0px"。
threshold: // 一个包含阈值的列表, 按升序排列, 列表中的每个阈值都是监听对象的交叉区域与边界区域的比率。当监听对象的任何阈值被越过时,都会触发callback。默认值为0。
})=>{}
思路
因为img标签的src一旦赋值就会请求图片地址,所以不能直接图片地址给到src,可先将图片地址都给到每一个图片元素的data-src
上,当图片移动到可视区时就将这个可视元素的data-src给到src上就可以了
结合组件库实现
// 懒加载功能
withLazy(bool) {
// 判断是否有lazy 有--触发懒加载
if (bool) {
this.$nextTick(() => {
// 创建监听视口
let imgObserve = new IntersectionObserver((entries) => {
// 判断监听元素是否位于视口中间
if (entries[0].isIntersecting) {
// 获取交集对象
let tarImg = entries[0].target
// 赋值加载url
tarImg.src = tarImg.dataset.src;
// 接触监视元素
// imgObserve.unobserve(tarImg)
// 卸载监视器对象
imgObserve.disconnect();
}
},{
root: this.$props.scrollContainer
})
// 监视图片
imgObserve.observe(this.$refs.img)
})
} else {
// 没有 则直接加载
this.$nextTick(() => {
this.$refs.img.src = this.commSrc
})
}