图片懒加载
认识图片懒加载
- 定义:在网页中视图之外的图片默认不加载,随着页面的滚动,图片进入了显示的范围,则触发图片的加载显示
- 目的:提高页面的加载速度,让用户体验感更好并且节省流量;比如在一些电商网站上需要展示大量的商品图片信息,如果打开网页时让所有图片一次性加载完成,需要处理很多次网络请求,等待加载时间比较长,用户体验感很差
- 原理:初始化时,图片标签的src不是真实的图片地址;而统一使用白图或者透明图代替;由于所有图片都使用这一张图片,只会发送一次请求,不会增加性能负担。然后将图片的真实路径绑定给一个自定义属性,例如data-url;然后监听滚动事件当图片元素进入视口时,就将src替换为真正的url地址。
图片懒加载的实现方法
实现方式:
- 滚动监听+scrollTop+offsetTop+innerHeight
<script>
/*
图片懒加载
1.获取所有的图片 每张图片的src属性中都统一绑定同一张白图或者透明图片 在自定义属性data-src上绑定真实的图片
2.图片懒加载要在window上绑定一个监听滚动事件
3.获取每一张图片距离浏览器窗口顶部的距离
浏览器可视区域的高度window.innerHeight
浏览器卷出高度document.documentElement.scrollTop||document.body.scrollTop
图片距离网页顶部的距离img.offsetTop
4.当某张图片距离顶部的距离小于浏览器的窗口的时候,那么该图片就加载显示
scrollTop+innerHeight > offsetTop,即图片在视口内,否则图片在可视区域外
*/
const imgs = document.querySelectorAll("img")
let flag = []
for (let i = 0; i < imgs.length; i++) {
flag[i] = true //使图片只加载一次
}
// 需要有一个滚动事件
window.addEventListener("scroll", (e) => {
// 要监听浏览器的滚动事件
// 获取每一张图片距离顶部的距离 => 遍历图片
for (let i = 0; i < imgs.length; i++) {
// 获取每一张图片距离浏览器顶部的距离
let imgTop = imgs[i].offsetTop
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop
let windowH = window.innerHeight
if (imgTop <(windowH + scrollTop)&& flag[i]) {
flag[i] = false //开关思想
console.log(i);
// 让img身上的data-src的地址显示到src的身上
imgs[i].src = imgs[i].dataset.src
}
}
})
</script>
- 滚动监听+getBoundingClientRect().top+window.innerHeight 当图片距离顶部的距离小于浏览器的窗口的时候,那么就图片加载显示
<script>
/*
图片懒加载
1.获取所有的图片 每张图片的src属性中都统一绑定同一张白图或者透明图片 在自定义属性data-src上绑定真实的图片
2.图片懒加载要在window上绑定一个监听滚动事件
3.获取每一张图片距离浏览器窗口顶部的距离
img.getBoundingClientRect().top => 获取img距离浏览器可视区域顶部的距离
window.innerHeight=>获取浏览器可视区域的高度
4.当某张图片距离顶部的距离小于浏览器的窗口的时候,那么该图片就加载显示
*/
const imgs = document.querySelectorAll("img")
let flag= []
for (let i = 0; i < imgs.length; i++) {
flag[i] = true //使图片只加载一次
}
// 需要有一个滚动事件
window.addEventListener("scroll",(e)=>{
// 要监听浏览器的滚动事件
// 距离浏览器可视区域顶部的距离 => 遍历图片
for(let i=0;i<imgs.length;i++){
// 获取每一张图片距离浏览器可视区域顶部的距离
let imgTop = imgs[i].getBoundingClientRect().top
// 浏览器可视区域的宽高
let windowH = window.innerHeight
if(imgTop<windowH && flag[i]){
flag[i] = false //开关思想
console.log(i);
// 让img身上的data-src的地址显示到src的身上
imgs[i].src = imgs[i].dataset.src
}
}
})
</script>
- 使用监听器来监听图片与视口的交叉 intersectionObserver() 监听图片与视口的交叉 => o.observe(img);监听到的图片是否交叉 => imgItem.isIntersecting;当为true时就用真正的图片路径替换src,然后使用o.unobserve(img) 不再监听视口交叉;这种方式比上面的方式更好,因为监听到后就可以关闭,而上面方式需要频繁监听scroll事件,会有一定的性能损耗;但是Intersection Observer API会有浏览器兼容问题!!
<script>
/*
使用监听器来监听图片与视口的交叉
创建监听器 => const o = new IntersectionObserver(callback)
监听图片与视口的交叉 => o.observe(img) => 在监听的过程当中应该是一张一张地监听
不监听图片与视口的交叉 => o.unobserve(img)
监听到的图片是否交叉 => imgItem.isIntersecting => 如果为true那么表示图片与视口交叉 否则就false
*/
// 监听到之后的处理 imgs=>你监听到的图片加工成的一个数组
const callback = imgs => {
console.log(imgs);
imgs.forEach(imgItem=>{
// 获取那一张监听到的图片
if(imgItem.isIntersecting){ //图片与视口交叉 此时要加载图片
// 将图片里面的data-src地址给src
imgItem.target.src = imgItem.target.dataset.src
// 不要再监听
o.unobserve(imgItem.target)
}
})
}
const o = new IntersectionObserver(callback)
// 监听页面当中的图片 获取所有图片
const images = document.querySelectorAll("img")
for(let i=0;i<images.length;i++){
// 每一张图片都要监听
o.observe(images[i])
}
</script>