图片懒加载
在网站开发中,经常有一些页面需要加载大量图片,所以会有大量图片请求,性能优化之一就有较少网络请求要求,所以为了减轻浏览器负担,我们需要根据用户可视区域视角,内的图片才发起请求,在网页末尾端底部的图片,用户是还看不到的,所以暂时没有必要网络请求;
懒加载优点
- 减轻浏览器负担,让内存先完成必须的工作
- 减少网络请求
- 较少并行时大量流量
实现关键逻辑:
- 可视区域高度
window.innerHeight
- img到顶部高度
getBoundingClientRect().top
- 观察或监听 img到顶部距离是否小于可视区高度
- img添加data-src默认属性 不设置src属性
- 可加载图片:
离顶部高度 < 窗口可视区
- 不加载图片:
离顶部高度 > 窗口可视区
代码实现
- 方案一
const images = document.querySelectorAll("img")
window.addEventListener("scroll", () => {
images.forEach(img => {
const imgTop = img.getBoundingClientRect().top
// 图片距离顶部高度 小于 可视区域高度
if (imgTop < window.innerHeight) {
img.setAttribute('src', img.getAttribute('data-src'))
}
});
})
-
缺点:每次滚动条的滚动,会触发大量的事件,如果页面需要加载很多内容就会导致任务的堆积,而且就算图片全部加载完了,但是还是会继续执行事件,及时做了判断删除代理
removeEventListener
但是又要IE的兼容判断,繁琐得不要不要 -
推荐最优方案:
new IntersectionObserver()
浏览器提供的观察者构造器,除了Internet其他主流浏览器都支持 详细文档
- 方案二(最佳案例)
const images = document.querySelectorAll("img")
// 创建一个观察者 观察元素每次 出现可视区域交叉时候(看到了和划走了交叉)
const observer = new IntersectionObserver((entries = []) => {
// 回调函数会触发2次,1:目标元素出现时触发, 2:元素看不见了触发
entries.forEach(item => {
// 观察到元素出现在可视区域
if (item.isIntersecting) {
const img = item.target
img.setAttribute('src', img.getAttribute('data-src'))
// 任务完成 关闭观察
observer.unobserve(img)
}
})
})
images.forEach(image => {
// 遍历每个img元素,并放入观察
observer.observe(image);
})
用户体验
- 以上就是懒加载方案实现了,当然这里并未结束,为了更好用户体验,我们可以给图片
加载时
,错误时
进行期间默认图片,加入loading…,error图片 - 继续深入体验优化:图片加载异常后,放一个重新加载功能,用户点击后,重新请求备案的src地址。
- 一些即时通讯项目或者大量图片网站项目中 可以把图片按流量大小分次加载
- 例如按:
默认(灰色)
->模糊
->完整
->高清
,等不同层级图片在不同时间完成渲染,合理浏览器渲染,就像生活避开高峰期,可以提前,或者拖后 - 例如微信聊天QQ,好友发来的图片第一时间一般都是模糊的,因为模糊图片流量更小,之后过几秒或者点击图片,才看到完整图片之内的优化
- 例如按:
推荐插件
v-lazy
vue插件react-lazyload
react插件