lazyload 图片懒加载

记得去年毕业面试的时候,有个面试官问我怎么优化网页性能,我提到了图片懒加载可以提升用户体验。后来人家问我怎么实现的,我懵逼脸,然后就没有然后了。

学前端过程中遇到很多技术点都没有深入研究,只是大概知道有那么个名词。最近做项目又想起这个问题,趁机做个总结吧。

懒加载的实现原理还是很简单的嘛。

lazyload 意义

图片资源在网站当中的占比是很高的,对于一个以设计驱动型的公司来讲,图片大小可能超过所有请求资源的50%,大大影响了网站的性能。

图片懒加载的意义就在于此,当图片进入视窗时再进行加载,从一定程度上减轻初始请求压力,加快页面呈现速度,提高用户体验。

你看,只有 banner 进入窗口内,才会去请求这个图片,是不是很爽。

lazyload 实现原理

实现图片懒加载的效果并不困难,几十行代码就可以搞定。

简单来说,先将图片真实的 src 隐藏,只加载占位图片。当图片进入视窗时,再将实际需要显示的图片路径附给 src 属性。

完整代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
/**
* picLazyLoad 图片懒加载,适用于img标签和背景图情况
*
* @property data-original: <String> 图片 url
* @property threshold: <Number> 进入可视区域提前加载的高度
* @property placeholder: <String> 用于背景图情况,占位图片 url
* @funcition callback(): 回调函数
*/

;(function($){
$.fn.picLazyLoad = function(settings){
var $this = $(this),
_winScrollTop = 0,
_winHeight = window.screen.height;

settings = $.extend({
threshold: 0,
placeholder: 'img/banner-blank.jpg',
callback: function(){
}
}, settings||{});

// 执行懒加载图片
lazyLoadPic();

// 滚动触发换图
$(window).on('scroll',function(){
_winScrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
lazyLoadPic();
});

// 懒加载图片
function lazyLoadPic(){
$this.each(function(){
var $self = $(this);
if($self.is('img')){
if($self.attr('data-original')){
var _offsetTop = $self.offset().top;
// threshold超过0,代表元素未出现在可视区域时就显示
if((_offsetTop - settings.threshold) <= (_winHeight + _winScrollTop)){
$self.attr('src',$self.attr('data-original'));
$self.removeAttr('data-original');
settings.callback($self);
}
}
}else{
if($self.attr('data-original')){ // 默认占位图片
if($self.css('background-image') == 'none'){
$self.css('background-image','url('+settings.placeholder+')');
}
var _offsetTop = $self.offset().top;
if((_offsetTop - settings.threshold) <= (_winHeight + _winScrollTop)){
$self.css('background-image','url('+$self.attr('data-original')+')');
$self.removeAttr('data-original');
settings.callback($self);
}
}
}
});
}
}
})(jQuery);

使用时,只需要在懒加载的元素上添加 lazyload 的 class,同时调用 lazyload() 方法即可。

1
2
3
4
5
6
7
8
9
10
11
12
<ul>
<li><img class="lazyload" src="img/banner-blank.jpg" data-original="img/banner-1.jpg"></li>
<li><img class="lazyload" src="img/banner-blank.jpg" data-original="img/banner-2.jpg"></li>
<li><img class="lazyload" src="img/banner-blank.jpg" data-original="img/banner-3.jpg"></li>
<li><img class="lazyload" src="img/banner-blank.jpg" data-original="img/banner-4.jpg"></li>
<li><img class="lazyload" src="img/banner-blank.jpg" data-original="img/banner-5.jpg"></li>
<li><img class="lazyload" src="img/banner-blank.jpg" data-original="img/banner-6.jpg"></li>
<li><img class="lazyload" src="img/banner-blank.jpg" data-original="img/banner-7.jpg"></li>
<li class="lazyload banner-8" data-original="img/banner-8.jpg"></li>
<li class="lazyload banner-9" data-original="img/banner-9.jpg"></li>
<li class="lazyload banner-10" data-original="img/banner-10.jpg"></li>
</ul>
1
$('.lazyload').picLazyLoad();

图片分为两种,一种是写在 <img> 标签里,另一种是写在 background 属性里,所以我们对不同来源的图片进行了分别处理。

占位图写在默认的 src 属性里,如果是背景图,则写在 background-image 属性里。占位图片会在一开始就进行加载,因为占位图通常是同一张图片,因此只需要请求一次即可。

而真正需要加载的图片写在自定义的属性,在这段代码当中,我们把它放在的 data-original 属性中。在图片加载以后,即 data-original 属性里的值写进 srcbackground-image 里,然后删除该属性。

1
$self.removeAttr('data-original');

(_offsetTop - settings.threshold) <= (_winHeight + _winScrollTop) 是图片是否显示的判断条件,这里 threshold 用来对显示时间进行控制。当 threshold 为 0,则图片进入视窗的同时进行加载;如果 threshold 大于 0,则图片在进入视窗之前就进行加载,属性值是提前加载的高度(px)。在文章开头的动图例子中,threshold 被设成 -50,所以你会发现当图片进入窗口的一段时间仍然是占位图片,直到 50px 以后才开始加载。

另外,setting 里设置了一些懒加载的相关参数。除了 threshold 以外,placeholder 用来背景图时的占位图,callback() 则是加载图片完成后的回调函数。如果你想让图片显示得不那么突兀,也可以加动画相关属性等等。