1. 图片懒加载
图片懒加载,当图片没有进入我们的视觉范围内的时候不进行加载,这样可以解决一次性加载大量图片带来的性能问题。
需要解决的问题:
- 如何判断在不在视口
- 如何在出现时进行图片加载
2. 实现方式
2.1 设置img的loading
给img元素设置loading属性,值为lazy
<img src="./example.jpg" loading="lazy" alt="lazyloading" height="200px" width="200px">
兼容性:
2.2 监听滚动 + 元素位置判断
2.2.1 位置判断
使用getBoundingClientRect()
img.getBoundingClientRect().top:图片距离视口顶部的距离window.innerHeight或document.documentElement.clientHeight:视口高度
如果 图片距离视口顶部的距离 < 视口高度,说明图片出现在视口中了
2.2.2 图片加载
<img data-src='xxx.jpg' />
使用data-*自定义属性,浏览器不会进行属性处理
js部分
const images = document.querySelectorAll('img')
window.addEventListener('scroll', (e)=>{
images.foreach(image =>{
const imageTop = image.getBoundingClientRect().top
if(imageTop < window.innerHeight){
const data_src = image.getAttribute('data-src')
image.setAttribute('src',data-src)
}
})
})
缺点: 滚动事件被频繁触发,加载后还是会被触发
可以增加防抖,debounce
2.2 使用 IntersectionObserver
IntersectionObserver 接口提供了一种异步观察目标元素与其祖先元素或顶级文档视口(viewport)交叉状态的方法。其祖先元素或视口被称为根(root)。
当一个 IntersectionObserver 对象被创建时,其被配置为监听根中一段给定比例的可见区域。一旦 IntersectionObserver 被创建,则无法更改其配置,所以一个给定的观察者对象只能用来监听可见区域的特定变化值;然而,你可以在同一个观察者对象中配置监听多个目标元素
创建一个观察者实例,构造函数接受一个callback,会在交叉状态更改的时候调用。观察者使用observer来对DOM节点进行观察,使用unobserve来取消观察。
HTML部分同上。
JS部分重点:
- 回调函数所接受参数为 子元素为对象的数组
- 使用对象的
isIntersecting来判断交叉状态 - 使用对象的
target来获取触发的元素
JS部分
const images = document.querySelectorAll('img')
// 或者
// const images = document.querySelectorAll('[data-src]')
const callback = (entries) => {
entries.forEach(entry => {
if(entry.isIntersecting){ // 根据entry对象的 isIntersecting 来判断是否交叉
const image = entry.target; // 根据entry对象的taget来获取目标图片节点
const data_src = image.getAttribute('data-src')
image.setAttribute('src', data_src);
observer.unobserve(image); // 停止观察已处理的元素
}
})
}
const observer = new IntersectionObserver(callback)
images.forEach(image => { // 观察者对所有图片进行观察
observer.observe(image)
})