前端优化之图片懒加载

http请求

若是你学过计算机网络你就会知道,咱们请求一个带有n张图片的html文件实际上会发送n+1次请求,由于在浏览器解析html的时候遇到了src,就会请求src后面的内容。html

设想一下若是咱们的页面有1000000张图片,那么若是等待这些图片响应成功并加载完成时延是很是大的,用户体验很是差。vue

那么咱们可不可让图片按需加载呢?当图片出如今可视区的时候再加载它而不是一开始就加载彻底部图片。git

图片懒加载

template:github

<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();
}
复制代码

以上就实现了一个图片懒加载,本篇文章就到这里,再见。markdown

桥豆麻袋,忽然发现一个严重的问题:滚动过程当中会不断触发lazyLoad对图片作一个遍历并判断,那么就会作无数次for循环,更可怕的是,修改一次src会发送一个请求,在滚动的时候咱们的for循环每次都从头判断并修改src请求图片,那么请求次数可想而知。网络

函数防抖

若是在滚动过程当中不断触发遍历并判断图片是否在可视区的监听事件,会耗费很大的性能,这里采用函数防抖:当用户中止滚动时统一遍历判断图片位置函数

debounce(fn) {
    // 函数防抖:用户中止操做以后触发
    clearTimeout(this.timer);
    this.timer = setTimeout(() => {
        fn();
    }, 1000);
}
复制代码

咱们能够将加载图片的方法放在debounce中oop

lazyLoad() {
    this.debounce(this.loadImg);
}
复制代码

这样当用户滚动页面时,松开手才会执行loadImg来遍历判断图片位置。性能

又出现了一个问题:若是用户在滚动时从页面底部上拉到顶部一直没有松手,那么在这期间都不会执行loadImg,这意味着页面的图片都不会显示,很是影响用户体验

防抖优化

咱们规定,若用户上拉高度大于500px那么就自动加载一次可视区内图片,这里咱们用oldScrollTop记录上次上拉高度

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
        }
    }
}
复制代码

结语

一个完整的优化版图片懒加载就完成了,我将该功能封装成了一个vue的插件

源码:vue-plugins

该插件库会持续更新,欢迎star & fork~

相关文章
相关标签/搜索