为了避免页面一次性向服务器发送大量请求而造成页面阻塞,我们需要控制请求数量,按照我们需要的量去加载图片。
-
懒加载的优点
提高前端性能,按需加载图片减轻服务器负担,提高页面加载速度。
-
懒加载的原理
图片的加载是依赖于
src
路径,我们可以设置一个暂存器,把图片路劲放到暂存器中,当我们需要这个图片加载显示时,再把路径赋值给src
,这样就能实现按需加载,也就是懒加载。我们通常使用html5中的data-
属性作为暂存器,例如src
的值默认是正在加载中的GIF,而真正的图片路径是保存在data-
中。 -
懒加载的实现
现在很多优秀的插件都能够实现懒加载的功能,但是不管方法如何,实现原理都是一样的。
JQuery
(不使用插件)
使用懒加载时,我们的src
的值默认是”正在加载中“的GIF,data-lazyload
是自定义属性,用于存放图片真实路径。如下面的代码。
<img src="loading.gif" data-lazyload="img.jpg">
我们首先要知道什么时候应该加载图片,什么时候不需要加载?
对于用户来说,看得到的地方才需要加载,看不到的地方加载了也是白白浪费资源。所以我们知道,在可视区域中,我们才需要加载图片。
如何判断图片是否在可是区域?我们可以利用元素的偏移高度,对比设备宽度加上滚动条高度来判断该元素是否处于可视区域中。
上图中,offsetTop
是图片元素的偏移高度,window.height()
是设备的高度,scrollTop
是滚动条与顶部的距离,因为滚动条在顶部,所以值为0。
当offsetTop
大于window.height() + scrollTop
时,图片就在可视区域之外。此时我们可以拉动滚动条,让文档向上移动,图片渐渐出现在可视区域之中。
图片元素的offsetTop
基本不变,如果设备高度加上滚动条与顶部的距离大于或者等于图片元素的偏移高度,我们就说它是在可视区域当中。所以有如下表达式:
img.offset().top <= window.height() + window.scrollTop(); // => true/false
接下来借助jQuery来实现
定义十张图片
./loading.gif
——加载中图片
data-lazyload
——自定义属性,存放图片路径
<div class="img"> <img src="./loading.gif" data-lazyload="https://dpic3.tiankong.com/67/cn/QJ6226943363.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic1.tiankong.com/zt/sg/QJ6235849453.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic1.tiankong.com/ul/ac/QJ6479383109.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic2.tiankong.com/1z/kb/QJ6401246638.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic1.tiankong.com/ut/zj/QJ6634256101.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic.tiankong.com/09/jh/QJ6635714192.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic3.tiankong.com/6k/i5/QJ6727412259.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic2.tiankong.com/av/fc/QJ6872601378.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic.tiankong.com/37/1u/QJ7100086664.jpg@!350h"> <img src="./loading.gif" data-lazyload="https://dpic1.tiankong.com/jt/7l/QJ7100510973.jpg@!350h"> </div>
JavaScript
1 // 监听滚动条事件 2 $(window).on('scroll', () => { 3 // 设置延时函数,防止加载过快,减轻服务器负担;为了效果明显,设置两秒延时 4 setTimeout(() => { 5 // 执行获取图片函数 6 getImg(); 7 },2000); 8 }) 9 10 // 获取图片函数 11 function getImg() { 12 // 遍历图片元素 13 $('.img img').each((index, item) => { 14 // 判断每一个图片元素是否在可视区域 15 if($(item).offset().top <= $(window).height() + $(window).scrollTop()) { 16 // 把暂存器data-lazyload的值赋值给img标签的src 17 $(item).attr('src', $(item).attr('data-lazyload')) 18 } 19 }) 20 }
上面的代码就是懒加载的实现方法,但是仍然有些瑕疵,比如延时函数没有及时清除、遍历图片元素时把已经加载的图片也一起遍历了、代码没有分模块等
下面进一步优化得到
引用:https://www.jianshu.com/p/8e2a73638153
1 // 第一次加载 2 getImg(); 3 4 var clock; // 设置一个延时函数节流 5 6 $(window).on('scroll', () => { 7 if (clock) { 8 // 如果拉动滚动条时,延时函数还未执行完,则清除 9 clearTimeout(clock); 10 } 11 clock = setTimeout(() => { 12 getImg(); 13 }, 2000) 14 }) 15 16 function getImg() { 17 // 返回没有data-isLoaded的img标签 18 // [1,2,3].not(1) => 返回不含有1的数组 [2,3] 19 $('.img img').not('[data-isLoading]').each((index,item) => { 20 if(isShow(item)) loading(item); 21 }) 22 } 23 24 function isShow(img) { 25 return $(img).offset().top <= $(window).height() + $(window).scrollTop() 26 } 27 28 function loading(img) { 29 $(img).attr('src', $(img).attr('data-lazyload')); 30 // 为已经加载的图片加一个标识,上面遍历图片的时候就会跳过已经加载了的图片 31 $(img).attr('data-isLoaded', 1); 32 }
演示
我们可以在控制台中明显看到,只有三张图片已经加载,滑动滚动条加载更多的图片
JQuery
(使用jquery.lazyload
)
引入jQuery
和jquery_lazyload
img
标签
data-original——图片地址
<img data-original="https://dpic3.tiankong.com/67/cn/QJ6226943363.jpg@!350h">
JavaScript
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/jquery_lazyload/1.9.3/jquery.lazyload.min.js"></script> <script type="text/javascript"> $(".img img").lazyload({ placeholder : "./loading.gif", //用图片提前占位 // placeholder,值为某一图片路径.此图片用来占据将要加载的图片的位置,待图片加载时,占位图则会隐藏 effect: "fadeIn", // 载入使用何种效果 // effect(特效),值有show(直接显示),fadeIn(淡入),slideDown(下拉)等,常用fadeIn threshold: 200, // 提前开始加载 // threshold,值为数字,代表页面高度.如设置为200,表示滚动条在离目标位置还有200的高度时就开始加载图片,可以做到不让用户察觉 }); </script>
总结:
Vue
中也有类似的插件vue_lazyload
,使用方法也是非常简单,实现的效果相同。
对比自己手写一个懒加载,插件明显较为方便。插件虽然好用,但我觉得先了解其实现原理,再使用插件,会让你受益匪浅。