js懒加载问题是个非常容易被问到的面试点,如果你还不清楚如何实现,不妨一起学习下
懒加载
所谓懒加载就是需要使用你的时候再加载,通常就是浏览网页的时候,你下拉很多图片的网页,边拉边加载,你可以看得出来下面的图片在展现你面前之前是没有加载出来的
自己实现
我们自行去网络上搜10张图,然后给10张图加个样式,让它们成一个块级元素,从上到下显示
xml
<style>
.img-item {
display: block;
height: 300px;
margin-top: 50px;
}
</style>
ini
<body>
<img class='img-item' src="https://th.bing.com/th?id=ORMS.5053ecdbef05fa7726aa489d27b52e40&pid=Wdp&w=612&h=304&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
<img class='img-item' src="https://th.bing.com/th?id=ORMS.c5db2c88af1a76f18d0efe02fcded91d&pid=Wdp&w=612&h=304&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
<img class='img-item' src="https://th.bing.com/th?id=ORMS.c5129de8701c4a933d92cd6bf832b233&pid=Wdp&w=300&h=156&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
<img class='img-item' src="https://th.bing.com/th?id=ORMS.afe7f6448d6eba0055cd8ce9ac9fdf62&pid=Wdp&w=300&h=156&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
<img class='img-item' src="https://th.bing.com/th?id=ORMS.e168b9c5da30772083104ed0f4ef0ecf&pid=Wdp&w=612&h=304&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
<img class='img-item' src="https://th.bing.com/th?id=ORMS.8025ce5a977b3826589022cede69e110&pid=Wdp&w=300&h=156&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
<img class='img-item' src="https://th.bing.com/th?id=ORMS.a58ae29e32e20a27d498eed19528ee3c&pid=Wdp&w=300&h=156&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
<img class='img-item' src="https://th.bing.com/th?id=ORMS.2049b527600b31b2cd863a380be59848&pid=Wdp&w=300&h=156&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
<img class='img-item' src="https://th.bing.com/th?id=ORMS.9f51912b8b6c19a9891b380ad526db85&pid=Wdp&w=612&h=304&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
<img class='img-item' src="https://th.bing.com/th?id=ORMS.1b6375ea147b5704f9d073a326e1fc2a&pid=Wdp&w=300&h=156&qlt=90&c=1&rs=1&dpr=1.25&p=0" alt="">
</body>
想要让这些图片进入到可视区内加载,进入之前不加载,就需要去动src,src有值了就一定会去加载,所以我们可以先把url放到另一个伪属性中去,等到了图片进入到可视区内再去把伪属性的url赋给src
如何获取元素的几何信息?
top和bottom都是自己到最顶部的距离,均已浏览器顶部为准
querySelector
是获取第一个元素,你会发现getBoundingClientRect
给你拿到了bottom和top属性
只要每个图片的top值比窗口的高度小,那么就代表着图片进入可视区范围内
ini
imgs.forEach(el => {
let rect = el.getBoundingClientRect()
if(rect.top < viewHeight) {
// 赋值逻辑......
}
})
data-original的值赋给src需要先交给第三方,这个第三方也需要是image标签,正常情况是需要createElement添加一个标签的,但是image标签非常之特殊,它本身就具有构造函数
ini
let image = new Image()
image.src = el.dataset.original
data-有个专有写法就是dataset,因此data-original就是dataset.original
接下来,通过load事件来确保image这个标签在创建完成之前是不会执行赋值的
ini
image.onload = function() {
el.src = image.src
}
这里肯定有小朋友要提出一个问题了,为何不直接写
el.src = el.dataset.original
。确实,这样写也没有问题,只不过浏览器对图片是有个缓存机制的,靠第三方的image标签纯粹是为了onload
,看图片是否被浏览器加载完毕,加载完毕才把值赋过去,如果直接赋值,加载的时候是空白的,加载是需要时间的。Image对象的src属性设置为要加载的url时,浏览器会异步开始加载该图片,这样图片可能已经被缓存了,从而提高了加载速度
图片一旦加载就不需要二次加载了,所以我们把data-original这个属性移除掉
arduino
el.removeAttribute('data-original')
因为imgs数组获取的时候就是获取带有data-original属性的图片
接下来就需要让用户滚动页面去触发这个事件,所以来一个监听滚动事件
javascript
document.addEventListener('scroll', lazyLoad)
最终代码如下
xml
<script>
let viewHeight = window.innerHeight
function lazyLoad() {
let imgs = document.querySelectorAll('img[data-original]')
imgs.forEach(el => {
let rect = el.getBoundingClientRect()
if(rect.top < viewHeight) {
let image = new Image()
image.src = el.dataset.original
image.onload = function() {
el.src = image.src
}
el.removeAttribute('data-original')
}
})
}
lazyLoad() // 页面初始加载时调用一次
document.addEventListener('scroll', lazyLoad)
</script>
边下划,src边被赋值,最终实现效果如下
最后
因为图片是非常占用浏览器性能的,懒加载的意义就是提高页面加载速度,降低资源浪费,提升用户体验。
懒加载的核心原理其实就是通过一个伪src属性,当图片到达了可视区范围内,就将伪src属性赋值给src
另外有不懂之处欢迎在评论区留言,如果觉得文章对你学习有所帮助,还请"点赞+评论+收藏"一键三连,感谢支持!
本次学习代码已上传至本人GitHub学习仓库:github.com/DolphinFeng...