使用原生js/jquery,实现高效率的图片占位加载,懒加载等功能。
在自己写这个功能之前,先试了下jquery lazyload,也看了一眼vue lazyload的文档。试了以后发现有2个问题
-
默认是会渲染全页面的img标签,当我的页面翻页次数多了以后,会出现明显卡顿,cpu占用高的情况。
-
监听onerror失效,因为jquery lazyload第一次加载完成占位图片后,就不再监听onerror了。vue Lazyload图片如果加载失败,可以触发error,但是只能传入error图片的参数,替换图片显示内容,不能执行代码。
于是我参考了一下这篇文章
js原生实现高性能懒加载(分步解析) - CSDN博客
从中理解到懒加载的基本款就包括以下几个步骤
-
初次加载使用占位符
-
监听当前浏览页面的滚动条的高度,来判断真实图片加载的时机
-
实现懒加载,替换src参数(必须发生在img的load步骤结束以后,否则占位图还未渲染,img还没有高度,占位会失效)
首先我直接用jquery写了一个最简单的图片占位功能。
1、首先默认只去加载 3x2像素 灰色的占位图片
- <img id="img666" src="1.jpg" alt="Park" onload="lazyLoad('666')" onerror="removeImg('666')">
2、当触发onload时再替换src
- function lazyLoad(id){
- var url = 'http://xxxx/'+id+'.jpg';
- $('#img'+id).attr('src',url);
- }
前面这样写还有一个小坑,正确的是,因为改变src会引起二次加载,二次加载成功还会触发onload,就会无限循环,所以加上判断可以在第二次循环时中断操作。
- function lazyLoad(id){
- // 因为改变src会引起二次加载,二次加载成功还会触发onload,就会无限循环,所以加上判断可以在第二次循环时中断操作。
- if($('#img'+id).attr('src') == '1.jpg'){
- var url = 'http://xxxx/'+id+'.jpg';
- $('#img'+id).attr('src',url);
- }
- }
3、当触发onerror直接移除整个img(css里实现了下一张图片自动往前移填充空缺)
- function removeImg(id){
- $('#img'+id).hide();
- }
当然也可以触发替换为404图片
- function errorImg(id){
- $('#img'+id).attr('src','404.jpg');
- }
那么同理,当404.jpg无法加载成功时,例如网络问题、图片url问题,也会触发onerror,同样会造成无限循环,所以保险的写法是
- function errorImg(id){
- $('#img'+id).attr('src','404.jpg');
- $('#img'+id).onerror = null;
- }
因为我一开始加载图片就是滚动到页面底部,才加载一批新的,所以不用再来一遍监听高度,显示图片了,但我还是大概看了一下CSDN大神
hawkey7
的完整代码。大致意思是监听滚动条的位置和图片的位置,来判断是否触发懒加载。而且必须发生在window.onload之后,否则第一批占位img还没加载完就执行懒加载,占位的效果就会失效,不美观。
- window.onload = function(){
- var scrollTop = window.scrollY;
- var imgs = Array.from(document.querySelectorAll('img'));
- lazyLoad();
- // 采用了节流函数
- window.addEventListener('scroll',throttle(lazyLoad,500,1000));
-
- function throttle(fun, delay, time) {
- var timeout,
- startTime = new Date();
- return function() {
-
- var context = this,
- args = arguments,
- curTime = new Date();
- clearTimeout(timeout);
- // 如果达到了规定的触发时间间隔,触发 handler
- console.log(curTime - startTime)
- if (curTime - startTime >= time) {
- fun();
- startTime = curTime;
- // 没达到触发间隔,重新设定定时器
- } else {
- timeout = setTimeout(fun, delay);
- }
- };
- };
- // 实际想绑定在 scroll 事件上的 handler
- // 需要访问到imgs , scroll
- function lazyLoad(){
- scrollTop = window.scrollY;
- imgs.forEach((item,index)=>{
- if( scrollTop===0 && item.dataset.src !== '' && item.offsetTop < window.innerHeight + scrollTop ){
- // alert()
- item.setAttribute('src',item.dataset.src)
- item.setAttribute('data-src','')
- }else if( item.dataset.src !== '' && item.offsetTop < window.innerHeight + scrollTop && item.offsetTop > scrollTop ){
- item.setAttribute('src',item.dataset.src)
- item.setAttribute('data-src','')
- }
- })
- }
- }