简介

在项目中有时候会遇到一个页面上有很多很多图片,如果所有的图片一次性加载,那么对网络是有一定要求的,并且每次加载图片都会对服务器发出请求;
所以,懒加载归根结底就是想要优化前端性能,只显示可视窗口内的图片,这样对用户而言图片加载速度明显变快了,而且可以可以节省流量,对服务器而言可以减少服务器的性能开销,因为请求的次数变少了;

最终效果

最终效果想要达到的是:每当图片快要进入可视窗口时,就加载图片,否则图片就不需要加载;

流程

想要达到最终效果,流程大致需要以下几步:

  1. 获取当前页面上所有img元素,并且做一个筛选,对已存在src属性并且src不为空的img元素进行过滤掉;
  2. 对筛选后的img元素进行分类,哪些是已经在视窗内的,哪些是还没有在视窗内的,可以等等在加载;
  3. 立刻加载已经在视窗内的img元素
  4. 监听浏览器的滚动事件,重复第二步,监听所有img元素,直至页面上所有img的src属性都有值为止;

正文开始

创建插件

//用一个立即执行函数将代码包裹起来,防止变量污染
(function(root,func,plugin){
    func(jQuery,plugin)
})(this,function(jQuery,plugin){
  //给$的fn添加一个名为prizeDraw的函数
  $.fn[plugin] = function(params,offset) {
  
  }
},'lazyload')

筛选img元素

在这一步中需要获取所有的img元素,并且进行筛选,将已存在src属性并且src不为空的img元素进行过滤掉掉,并且如果img标签没有指定的属性,那么也过滤掉

//视窗高度
let windowHeight = () => $(window).height();
$.fn[plugin] = function (params,offset) {
    if(!(typeof params === "string" && typeof offset === "number")) return;
		//执行懒加载函数
    lazyloadFunc(this,params,offset);
};

function lazyloadFunc(jqDom, params, offset){
    //取得所有src为空,或者没有src属性的img元素
    const imgfilter =  imgfilterFunc(jqDom);
}

function imgfilterFunc(dom){
    const arr = [];
    for(let i = 0;i < dom.length;i++){
        if(!$(dom[i]).attr("src") && $(dom[i]).attr("data-src")){
            arr.push(dom[i])
        }
    }
    return arr;
}

此时获得的imgfilter变量,就是所有需要实现懒加载的img元素

img元素分类

在这一步,需要对imgfilter变量中的所有img进行分类:

  • 如果图片已经在视窗内,那么这些在视窗内的图片就是需要立刻加载的;
  • 如果图片还没有进入视窗内,那么这些图片可以放一放,晚点再说,反正用户也看不到;
function lazyloadFunc(jqDom, params, offset){
      //取得所有src为空,或者没有src属性的img元素
      const imgfilter =  imgfilterFunc(jqDom);

      //对图片进行筛选
      const imgObj = imgType(imgfilter, offset);
  }

//将该网页上所有的img进行分类
//一种是已经在视窗内,需要马上加载显示的,另一种是不在视窗内,可以等滚动条滚动到接近的时候再显示
function imgType(arr, offset){
    const arrtype = {
        nowload:[],
        lazyload:[]
    };
    //滚动条距离顶部的距离
    let scrollTop = $(window).scrollTop();

    for(let i = 0;i<arr.length;i++){
        let item =  $(arr[i]).offset().top;
      	//offset变量是设定的加载提前量,代表img在进入视窗内前offset像素时加载
        if(item - scrollTop - offset > windowHeight()){
            arrtype.lazyload.push(arr[i]);
        }
        else{
            arrtype.nowload.push(arr[i]);
        }
    }
    return arrtype;
}

返回的对象imgObj中就分好了,哪些是需要立刻加载的,哪些是可以等等加载的;

立刻加载视窗内img

对imgObj中所有需要立刻加载的img进行加载

function lazyloadFunc(jqDom, params, offset){
    //取得所有src为空,或者没有src属性的img元素
    const imgfilter =  imgfilterFunc(jqDom);

    //对图片进行筛选
    const imgObj = imgType(imgfilter, offset);
  
    //立刻加载已在视窗内的
    loadImgNow(imgObj.nowload, params);
}
//对需要加载的进行立刻加载
function loadImgNow(arr, params){
    arr.forEach(el => {
        $(el).attr("src",$(el).attr(params))
    });
}

这个所谓的加载,就是将预设在data-src中的图片路径赋值给src属性,这样img就可以加载图片了

监听滚动事件

监听滚动事件,每一次滚动的时候,都会获得页面上所有还没有加载src的img元素,之后再对没有加载的img元素进行分类,判断哪些需要加载,哪些还可以等等

$.fn[plugin] = function (params,offset) {
    if(!(typeof params === "string" && typeof offset === "number")) return;

    lazyloadFunc(this,params,offset);
		
  	//监听滚动事件,再次执行加载事件
    $(window).scroll(() => {
        lazyloadFunc(this,params,offset);
    })
};

优化

在所有的图片都已经被加载玩了之后,每次滚动滚动条的时候,还会进行筛选,这显然是不可理的,既然所有图片都已经加载完了,那么此时就不需要再筛选数组了,因此加一个开关

$(window).scroll(() => {
    if(flg){
        lazyloadFunc(this,params,offset);
    }
})
function lazyloadFunc(jqDom, params, offset){
    //取得所有src为空,或者没有src属性的img元素
    const imgfilter =  imgfilterFunc(jqDom);
		
  	//如果图片进行筛选后,发现所有图片都有不为空的src属性了,那么就代表所有图片都已经加载完毕了
    if(!imgfilter.length){
        flg = false;
        return;
    }

    //对图片进行筛选
    const imgObj = imgType(imgfilter, offset);
    //立刻加载已在视窗内的
    loadImgNow(imgObj.nowload, params);
}

总结

图片的懒加载想要解决的一个问题是优化前端的性能,能给用户带来更好的体验,同时可以减少服务器压力,因此如果项目中如果哪个页面存在大量的图片,那么就可以考虑引入懒加载机制,提高用户体验;