手写一个vue.js适用的简化版图片懒加载插件

294 阅读3分钟

何为懒加载

懒加载意在‘懒’字,即页面渲染时先用指定占位图代替,并不把页面内的所有图片都加载出来。而是‘按需’加载,当图片出现在可视区域,或者距离可视区域一定像素时才加载

其有何用

前面已介绍到,懒加载使得图片出现在可视区域时才加载。相较于一次性全部加载,最大的作用就是减少服务器压力,减少带宽。(在远古时代,img标签还会阻塞页面渲染,现代浏览器已经将img标签加载改为异步)

如何实现

前面提到,所有图片先用占位图加载,当图片出现在可视区域的时候再加载图片真实地址

这里就涉及到了两个点:

  • 元素是否处于可视区域判断
  • 元素属性更换

先把html代码写一下,html并无特殊之处。用data-src来存放图片真实地址,等到时候的时机再把真实地址渲染上去。至于lazyload和lazyname这两个属性,稍后会介绍

<img class="" src="/img/default.png" :data-src="item.img" lazyload="0" lazyname="lazyname" alt=""/>

现在把逻辑代码写一下

function lazyload(lazyname, viewDistance) {
    const seeHeight = document.documentElement.clientHeight; // 窗口高度
    const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; // 已经滑动的高度
    document.querySelectorAll('img').forEach(el => {
        if (el.attributes['data-src'] && el.src !== el.attributes['data-src'].nodeValue) {
            if (el.offsetTop < seeHeight + scrollTop) {
                var img = document.createElement('img');
                const src = el.src;
                img.src = el.attributes['data-src'].nodeValue;
                img.onload = e => {
                    el.src = el.attributes['data-src'].nodeValue;
                };
                img.onerror = e => {
                    el.attributes['data-src'].nodeValue = src;
                };
            }
        }
    });
}

以上就是一个简易且粗暴的懒加载组件,但细细想想,有没有能改进的地方呢?还记不记得html标签里有两个没有用到的属性呢,稍做修改出个 V2版本

function lazyload(lazyname, viewDistance) {
    const seeHeight = document.documentElement.clientHeight; // 窗口高度
    const scrollTop = document.documentElement.scrollTop || document.body.scrollTop; // 已经滑动的高度
    let d = viewDistance || 100; // 元素距离可视区域的加载距离
    let n = lazyname;
    let select = document.querySelectorAll("img[lazyload='0'][lazyname=" + n + ']');
    for (let i = 0; i < select.length; i++) {
        if (select[i].offsetTop < seeHeight + scrollTop + d) {
            if (select[i].attributes['data-src'] && select[i].src !== select[i].attributes['data-src'].nodeValue) {
                var img = document.createElement('img');
                const src = select[i].src;
                img.src = select[i].attributes['data-src'].nodeValue;
                img.onload = e => {
                    select[i].src = select[i].attributes['data-src'].nodeValue;
                    select[i].setAttribute('lazyload', 1);
                };
                img.onerror = e => {
                    select[i].attributes['data-src'].nodeValue = src;
                };
            }
        } else {
            return;
        }
    }
}

拎几条改造后的语句出来

let select = document.querySelectorAll("img[lazyload='0'][lazyname=" + n + ']');
// 通过lazyload属性将img标签选择器做了一次筛选,从而减少选中节点的长度,提高遍历的速度
// 而lazyname则是对img标签做精准筛选,即按需对img标签进行懒加载

img.onload = e => {
    select[i].src = select[i].attributes['data-src'].nodeValue;
    select[i].setAttribute('lazyload', 1);
};
// 这里将加载完成的img标签 lazyload属性值替换成1  以配合上面的选择器规则使用

至此,一个简易的懒加载器就完成了。当然,还存在很多可优化点,比如防抖等,不过这些就暂时不展开

笔者也将该懒加载器投入生产环境中,就目前来讲,没遇到什么问题。如读者朋友在使用或阅读过程有什么建议,欢迎留言,笔者看到一定及时回复