js-图片懒加载的实现
目录
2.懒加载的优点
3.如何实现图片懒加载
1.什么是图片懒加载
指当页面加载数据时,只先加载浏览器可视区的图片,而不是直接加载页面中所有图片。只有当鼠标滚轮往下滑,才加载后面的图片。
2.懒加载的优点
使用图片懒加载可以优化页面的渲染速度,减少图片的加载时间以及加载体积(因为你不用等所有的图片都加载好,只需要当前可视区要用到的图片加载好即可,减少服务器发送请求获取图片信息的次数)。同时可以为客户节省流量。
3.如何实现图片懒加载
- 第一种最简单直接的方式便是监听 scroll 事件,当图片到浏览器顶部的距离小于浏览器可视窗口的高度时,加载图片
(document.getBoundingClientRect().top < window.innerHeight)
具体做法:先将在 <img /> 标签中自定义一个属性 data-src ,放实际图片的地址,等需要加载图片的时候再将 data-src 中的值,赋值给 src 属性。
<img data-src="src/views/images/1.jpg" />
(注:Vue 项目中要 img 的 src 属性的路径要写完整,从脚手架 src 文件夹一级一级往下写,因为后续改完路径之后服务器是直接拼接上地址渲染的,不会识别 ' ./ ' 具体指的是哪个路径)
完整代码
<img data-src="src/views/images/1.jpg" /><br />
<img data-src="/src/views/images/2.jpg" /><br />
<img data-src="/src/views/images/3.jpg" /><br />
<script>
const imgs = document.querySelectorAll("img");
window.addEventListener('scroll',()=>{
imgs.forEach(img => {
if(img.getBoundingClientRect().top < window.innerHeight) {
const data_src = img.getAttribute('data-src');
img.setAttribute('src',data_src);
console.log('触发'); // 测试触发次数
}
})
})
</script>
这个方法虽然简单,但弊端也有,每次拖动滚动条,只要图片是在可视窗口内都会触发,但实际上只要是加载过的图片,只需要加载一次就好了,这样无疑是增加了服务器的请求数量。由此引出第二个优化方法。
- 第二个方法是使用浏览器提供的构造函数 IntersectionObserver (交叉观察)
目标元素和可视窗口之间的产生交叉区域(也就是目标元素出现在可视区域时),交叉区域的出现和消失会调用 IntersectionObserver 的回调函数
- 首先实例化一个 IntersectionObserver 对象 ob
- 当需要观察目标元素是否进入或退出可视区时,调用 ob 对象的 observe 方法,当不需要观察时调用 ob.unobserve 方法。
- 这样我们在图片第一次加载后就可以停止观察了,就不会造成反复观察反复加载。
const ob = new IntersectionObserver(function callback(changes){});
// 观察元素
ob.observe(element);
// 不观察元素
ob.unobserve(element);
callback 回调函数有一个参数(changes)是数组,每个成员都是一个 IntersectionObserverEntry 对象。举例来说,如果同时有两个被观察的对象的可见性发生变化,changes 数组就会有两个成员。
循环遍历参数 changes 中每一个成员,当该成员的 isIntersecting = true 则说明该回调函数所属的目标元素已经出现,将目标元素 img 的真正路径赋值,加载渲染图片。只要目标元素出现过一次已经渲染过了,就可以停止观察了,避免重复加载。
完整代码
const imgs = document.querySelectorAll("img");
const observer = new IntersectionObserver(callback); // 实例化
function callback(entries) {
// 循环遍历回调函数中每一个成员
entries.forEach((entry) => {
if (entry.isIntersecting) {
const image = entry.target; // 提取回调函数所属的目标元素
const data_src = image.getAttribute("data-src");
image.setAttribute("src", data_src); // 修改回调函数所属的目标元素 img 标签的 src
observer.unobserve(image); // 关闭目标元素的观察
console.log('触发'); // 测试触发次数
}
});
}
imgs.forEach((img) => { // 循环所有 img 标签,观察每个 img 标签
observer.observe(img);
});
测试结果:三张图片只会触发三次,达到预期
lubxx: 方法二解决,牛
1H1R1M: 为啥我配置了watchfiles还是不会自动刷新
下岗鹦鹉再就业: 方法二解决,牛批
Phy_DE: 方式二解决,感谢
John_Woo_: 唯一真神