简介
在项目中有时候会遇到一个页面上有很多很多图片,如果所有的图片一次性加载,那么对网络是有一定要求的,并且每次加载图片都会对服务器发出请求;
所以,懒加载归根结底就是想要优化前端性能,只显示可视窗口内的图片,这样对用户而言图片加载速度明显变快了,而且可以可以节省流量,对服务器而言可以减少服务器的性能开销,因为请求的次数变少了;
最终效果
最终效果想要达到的是:每当图片快要进入可视窗口时,就加载图片,否则图片就不需要加载;
流程
想要达到最终效果,流程大致需要以下几步:
- 获取当前页面上所有img元素,并且做一个筛选,对已存在src属性并且src不为空的img元素进行过滤掉;
- 对筛选后的img元素进行分类,哪些是已经在视窗内的,哪些是还没有在视窗内的,可以等等在加载;
- 立刻加载已经在视窗内的img元素
- 监听浏览器的滚动事件,重复第二步,监听所有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);
}
总结
图片的懒加载想要解决的一个问题是优化前端的性能,能给用户带来更好的体验,同时可以减少服务器压力,因此如果项目中如果哪个页面存在大量的图片,那么就可以考虑引入懒加载机制,提高用户体验;