如果你一打开文章,里面有10000张图片,那么如果等待这些图片响应成功并加载完成这个是非常慢的,而且图片的加载是同步的,加载时会阻塞浏览器继续向下解析,用户体验非常差。
那么我们可以让图片按需加载,当图片出现在可视区的时候再加载它而不是一开始就加载全部图片
vue解决方案:
template:
<div @scroll="lazyLoad" ref="lazy">
<img v-for="(src, index) in imgs" src="##" :dataSrc="src" :key="index">
<!--more img-->
</div>
改变图片src
监听最外层div的滚动事件,触发滚动时遍历图片检测图片位置,若在可视区内则显示
loadImg() {
var img = this.$refs.lazy.getElementsByClassName("lazyImg");
// 已滚动高度+可视区高度
var top = this.$refs.lazy.scrollTop + this.$refs.lazy.clientHeight;
for(var i = 0; i < img.length; i++) {
if(img[i].offsetTop <= top) { // 在可视区内则显示图片
img[i].src = img[i].getAttribute("datasrc");
}
}
},
lazyLoad() {
this.loadImg();
}
函数防抖:
如果在滚动过程中不断触发遍历并判断图片是否在可视区的监听事件,会耗费很大的性能,这里采用函数防抖;当用户停止滚动时统一遍历判断图片位置
debounce(fn) {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
fn();
},1000)
}
我们可以将加载图片的方法放在debounce中
lazyLoad(){
this.debounce(this.loadImg);
}
这样当用户滚动页面时,松开手才会执行loadImg来遍历判断图片位置。
又出现了一个问题;如果用户在滚动时从页面底部上拉到顶部一直没有松手,那么在这期间都不执行loadImg.这意味着页面的图片都不会显示,非常影响用户体验
防抖优化:
lazyLoad() {
// 如果上拉距离大于500px则自动加载
if(this.$refs.lazy.scrollTop - this.oldScrollTop > 500) {
this.loadImg();
this.oldScrollTop = this.$refs.lazy.scrollTop; // 更新oldScrollTop
} else { // 如果向下拉但小于500px则防抖加载
this.debounce(this.loadImg);
}
}
下拉优化:
当用户下拉的时候我们并不需要执行lazyLoad,因为我们之前的图片已经加载过了,所以可以修改一下lazyLoad
lazyLoad() {
// 如果上拉距离大于500px则自动加载
if(this.$refs.lazy.scrollTop - this.oldScrollTop > 500) {
this.loadImg();
this.oldScrollTop = this.$refs.lazy.scrollTop;
} else if(this.$refs.lazy.scrollTop - this.oldScrollTop < 0) { // 如果向下拉则不做操作
return ;
} else { // 如果向下拉但小于500px则防抖加载
this.debounce(this.loadImg);
}
}
减少遍历个数
最重要的优化已经做完了,但是还可以从一些小细节更加优化一下,我们的loadImg
方法中每次都是从0号下标开始遍历检查图片,但是在用户上拉操作之后一部分图片已经被加载了,就不需要再次去检查了。
我们可以用一个变量len
记录上一次被加载后的最后一个图片,然后修改一下loadImg
loadImg() {
var img = this.getImages();
var top = this.$refs.lazy.scrollTop + window.screen.height;
// 从len开始检查
for(var i = this.len; i < img.length; i++) {
if(img[i].offsetTop <= top) {
img[i].src = img[i].getAttribute("datasrc");
this.len = i; // 更新len
}
}
}
总结下:
先将img标签中的src链接设为同一张空白图片,将其真正的图片地址存储再img标签的自定义属性中(比如data-src)。
当js监听到该图片元素进入可视窗口时,即将自定义的data-src属性存为src中,达到懒加载的效果。