JS实现图片懒加载插件

一、前言
我在前几篇博客的记录中,有说自己在做一个图片懒加载的功能,然后巴拉巴拉的遇到哪些问题,结果做完了也没对懒加载这个功能做一些记录,所以这篇文章主要针对我所实现的思路,以及代码做个记录,实现不佳之处还望见谅和指出。
二、实现原理与相关问题
1.做成一个组件还是service?
公司框架是angular,类似于图片懒加载这类较通用的功能,肯定得保证复用性与可拓展性,同事建议做成组件,哪张图片需要懒加载给这个图片添加组件名;我心想,那repeat出来一百张图,那岂不是瞬间瞬间100个组件同时运行,内存爆炸....听起来不是很优化的感觉。想了下,还是做成service,哪里需要注入我的service,调用我提前提供好的方法即可。

基本功能流程图如上,提前为需要懒加载的图片统一添加lazyImg-src="真实图片地址">属性,页面加载完成获取所有有lazyImg-src属性的dom,获取dom操作只会执行一次,我不想每次滚动都会反复获取dom,这样太友好。
页面加载完成会自调一次懒加载函数,之后就交给滚动事件触发,当一个dom元素的图片替换完成,就将此dom从数组中删除,懒加载函数执行的前置条件为dom数组不为空,那么当第一次懒加载完后无论用户怎么滚动,核心代码不会再执行。
2.如何判断图片是否在视图框内?
这个问题可以说是懒加载的核心问题,弄懂这个,功能已经做了一大半了,我们来看一个图:

判断一张图是否在视图范围内,需要判断X轴与Y轴的进入,离开的两种情况,加起来就是四个条件,只要同时满足,则元素一定在视图范围内。
3.怎么使用?
给需要懒加载的元素添加lazyImg-src属性,里面存放真实的图片地址,为了更好的体验,你可以将图片路径设置为一张loading的图片,在懒加载时再进行替换。
调用lazyload方法,并传入视图对象,什么意思呢,比如下面给出的demo代码中,位置参照对象是window,视图对象是ul,判断的是每张img。
当触发滚动事件时,监听的是ul的滚动条,步骤如下,引入JS
先获取视图对象,例如:
const viewDom = document.querySelector('.container');
然后调用方法lazyload(viewDom )即可。
你也可以不传递视图对象,那么此时视图对象会默认为window,也就是说当触发滚动事件时,监听的是window的滚动条。
三、实现代码
效果图,此时的滚动事件监听的是ul的滚动条。随着滚动,netWork中可以看到img在一张张加载。

HTML部分,图片自己准备,懒加载JS记得引入
<ul class="container">
<li><img src="img/timg.gif" alt="1" lazyImg-src="img/1.jpg"></li>
<li><img src="img/timg.gif" alt="2" lazyImg-src="img/2.jpg"></li>
<li><img src="img/timg.gif" alt="3" lazyImg-src="img/3.jpg"></li>
<li><img src="img/timg.gif" alt="4" lazyImg-src="img/4.jpg"></li>
<li><img src="img/timg.gif" alt="5" lazyImg-src="img/5.jpg"></li>
<li><img src="img/timg.gif" alt="6" lazyImg-src="img/6.jpg"></li>
<li><img src="img/timg.gif" alt="7" lazyImg-src="img/7.jpg"></li>
<li><img src="img/timg.gif" alt="8" lazyImg-src="img/8.jpg"></li>
<li><img src="img/timg.gif" alt="9" lazyImg-src="img/9.jpg"></li>
<li><img src="img/timg.gif" alt="10" lazyImg-src="img/10.jpg"></li>
</ul>
CSS部分:
body{
position:relative;
padding:0;
margin:0;
display: table;
}
.container{
list-style: none;
height: 400px;
width: 250px;
overflow: auto;
margin-top:200px;
}
.container>li{
margin-bottom: 10px;
}
.container>li>img{
background-color: #e4393c;
width: 200px;
height: 200px;
}
JS部分,别被变量的数量吓到,搞懂原理其实真的不复杂,或者打断点跟着跑一遍。
//处理图片懒加载
function lazyload (option) {
//如果不传递视图对象,则默认视图对象为window
var viewDom = option || window,
scroll_top, //滚动条Y轴距离
scroll_left, //滚动条X轴距离
viewDomWidth, //视图宽
viewDomHeight,//视图高
viewDomLeft, //视图左偏移量
viewDomTop, //视图上偏移量
imgWidth, //img宽
imgHeight, //img高
imgLeft, //img左偏移量
imgTop, //img上偏移量
imgArr = [],
doc = document.documentElement; //获取视图元素宽高,左上偏移量,分为window或普通dom两种情况
if (viewDom === window) {
viewDomWidth = doc.clientWidth;
viewDomHeight = doc.clientHeight;
viewDomLeft = doc.offsetLeft;
viewDomTop = doc.offsetTop;
}else{
viewDomWidth = viewDom.offsetWidth;
viewDomHeight = viewDom.offsetHeight;
viewDomLeft = viewDom.offsetLeft;
viewDomTop = viewDom.offsetTop;
}; /**
* @desc 将nodeList转为数组,方便操作
* @param {object} data nodelist对象
*/
function nodeListToArr(data) {
var arr = [];
try{
//ie8及以下不支
arr = Array.prototype.slice.call(data);
}catch(e){
//兼容写法
var len = data.length;
for(var i = 0; i < len; i++){
arr.push(data[i]);
}
};
return arr;
};
//取得所有需要懒加载的dom元素
var imgNode = document.querySelectorAll("[lazyImg-src]");
imgArr = nodeListToArr(imgNode);
//替换路径函数,懒加载核心函数
function replaceUrl () {
//只有img数组不为空,才会执行替换路径的操作
if(imgArr.length){
var i = 0;
//获取视图元素滚动条滚动距离
if (viewDom === window) {
scroll_top = doc.scrollTop;
scroll_left = doc.scrollLeft;
}else{
scroll_top = viewDom.scrollTop;
scroll_left = viewDom.scrollLeft;
};
//遍历需要懒加载的dom节点
for (; i<imgArr.length; i++) {
//获取当前元素的宽高
imgWidth = imgArr[i].offsetWidth;
imgHeight = imgArr[i].offsetHeight;
//当前元素随着滚动的变化的偏移量为
imgLeft = imgArr[i].offsetLeft - scroll_left;
imgTop = imgArr[i].offsetTop - scroll_top;
//横向判断是否进入视图元素
var boundaryLeft = imgLeft + imgWidth - viewDomLeft;
var boundaryRight = viewDomLeft + viewDomWidth - imgLeft;
//同理纵向判断是否进入视图元素
var boundaryTop = imgTop + imgHeight - viewDomTop;
var boundaryBottom = viewDomTop + viewDomHeight - imgTop;
if(boundaryLeft>0 && boundaryRight>0 && boundaryTop>0 && boundaryBottom>0) {
//替换图片路径,添加判断,img替换src,非img替换background
if(imgArr[i].nodeName === "IMG"){
imgArr[i].src = imgArr[i].attributes['lazyimg-src'].value;
}else{
//不是图片的替换背景图
// imgArr[i].style.backgroundImage = imgArr[i].attributes['lazyimg-src'].value;
};
//操作完一项就删除一项,同时重置i;
imgArr.splice(i,1);
i -= 1;
};
};
};
};
//自调
replaceUrl();
//添加事件监听
viewDom.addEventListener("scroll",replaceUrl);
};
//测试调用,默认绑定window,或传递你需要监听的dom对象,调用就2步
var container = document.querySelector(".container");
lazyload(container);
四、遇到的一些问题
1.判断元素是否在视图内,就Y轴而言,随着滚动条向下滚动,可以说img元素距离参照物上端会越来越近,也就说这个img上偏移量会越来越小,然后我果断用了JS的offsetTop属性来获取上偏移量,结果踩了个坑,但用JQ的offset().top却没问题,原因是offsetTop获取的是img初始位置的上偏移量,不随滚动条滚动变化,而offset().top是变化的,具体想知道JS offsetTop与offset().top不同以及怎么通过JS获取可变的上偏移量,可以阅读博主这篇文章。
JQ的offset().top与js的offsetTop区别详解
2.此实现方法需要一开始获取所有需要懒加载的dom元素,而公司用的angular,angular有自己的生命周期,怎么保证我获取dom的时候,所有angular模板以及指令已完全渲染完成呢?有兴趣可以阅读博主这篇文章:
angular监听dom渲染完成,判断ng-repeat循环完成
3.通过querySelector获取的dom其实是一个domList对象,然而我在处理完每个dom后想要删除此项,而domList对象不支持数组方法,怎么把domList转为数组对象,可以看这篇文章。
那么大概记录这么多了,本人本地运行是没问题的,有问题欢迎大家指出。
JS实现图片懒加载插件的更多相关文章
- Js 之图片懒加载插件
一.PC端(lazyload) 1.引入js文件 <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.m ...
- jQuery图片懒加载插件jquery.lazyload.js使用实例注意事项说明
jQuery图片懒加载插件jquery.lazyload.js使用实例注意事项说明 jquery.lazyload.js是一个用JavaScript编写的jQuery插件.它可以延迟加载长页面中的图片 ...
- 图片懒加载插件lazyload使用方法
图片懒加载插件lazyload使用方法 一.如何使用: Lazy Load 依赖于 jQuery.引入文件 <script type="text/javascript" sr ...
- Vue图片懒加载插件
图片懒加载是一个很常用的功能,特别是一些电商平台,这对性能优化至关重要.今天就用vue来实现一个图片懒加载的插件. 这篇博客采用"三步走"战略--Vue.use().Vue.dir ...
- 页面性能优化-原生JS实现图片懒加载
在项目开发中,我们往往会遇到一个页面需要加载很多图片的情况.我们可以一次性加载全部的图片,但是考虑到用户有可能只浏览部分图片.所以我们需要对图片加载进行优化,只加载浏览器窗口内的图片,当用户滚动时,再 ...
- 原生js开发,无依赖、轻量级的现代浏览器图片懒加载插件,适合在移动端开发使用
优势 1.原生js开发,不依赖任何框架或库 2.支持将各种宽高不一致的图片,自动剪切成默认图片的宽高 比如说你的默认图片是一张正方形的图片,则各种宽度高度不一样的图片,自动剪切成正方形. 完美解决移动 ...
- js, javascript 图片懒加载 实例代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- js实现图片懒加载
大型购物网站都会采用图片懒加载技术来优化网站首页打开速度,以提高用户体验,那么具体是怎么实现的呢,我们一探究竟. html结构(div包裹一层用来显示背景图片,等待图片加载完成后,显示真实图片) &l ...
- 原生js实现图片懒加载+加入节流
这两天在学习图片的懒加载实现,看了很多大佬的博客,终于有了点成果.现在用了其中一位大佬的文章中的代码实现了图片懒加载并且在其基础上加入了节流函数. 原理就不多讲了,有需要的可以去大佬的文章看看.大佬文 ...
随机推荐
- 选择困难症的福音——团队Scrum冲刺阶段-Day 2
选择困难症的福音--团队Scrum冲刺阶段-Day 2 今日进展 编写提问部分 如何将不同的问题选项连接到不同的下一个问题 如何保证问题的链接不会弄丢 登陆注册界面 完成密码可见与不可见的更改 ui界 ...
- mysql开启调试日志general_log开启跟踪日志
general_log = 1 general_log_file = /tmp/umail_mysql.log 有时候,不清楚程序执行了什么sql语句,但是又要排除错误,找不到原因的情况下, 可以在m ...
- linux就该这么学,第六天了
今天学了第六天了,主要讲计划任务了,,at,命令,单次有效,一次性的,crontd服务(周期性)计划任务,crontab -e创建,编辑计划任务.crontab -l查看计划任务,crontaab - ...
- idea连接操作数据库
场景 本文主要以DB2作为演示,其他数据库大同小异: 网上有很多推荐DB2的连接软件工具,但是因为DB2的使用场景不多,这次是在做数据资产管理的数据质量分析时使用到,在做数据交换时要在DB2中建表并同 ...
- win7启动时怎么自动进入桌面
1.按Win+R组合键,打开“运行”对话框.(Win是键盘下方左右两边的两个印有微软标志的键) 2.Windows XP/2003/2008/2008R2输入"control userpas ...
- 学习Acegi应用到实际项目中(4)
此节介绍:ConcurrentSessionFilter. 在Acegi 1.x版本中,控制并发HttpSession和Remember-Me认证服务不能够同时启用,它们之间存在冲突问题. 在一些应用 ...
- undo空间满的处理方法(含undo的学习与相关解释)
1.查看数据库当前实例使用的是哪个UNDO表空间: show parameter undo_tablespace 2.查看UNDO表空间对应的数据文件和大小 pages col file_name f ...
- MFC 不同窗体之间变量调用
应用场景: (1)主对话框包含一个Tab控件,Tab控件用来切换显示若干子对话框,子对话框类的成员需要互相访问. (2)或者程序中包含多个类,各类之间需要互相访问. 方法1-定义指针成员变量: 详情参 ...
- FFmpeg原始帧处理-滤镜API用法详解
本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10429145.html 在FFmpeg中,滤镜(filter)处理的是未压缩的原始音视频 ...
- SVN 客户端 TortoiseSVN 的安装和使用
关于 参考博客:TortoiseSVN新人使用指南 TortoiseSVN 是一个 Apache Subversion(SVN)客户端,实现为Windows外壳扩展.它直观且易于使用,因为它不需要Su ...