几个月前实现的一个图片懒加载库lazyload.js
,github 地址。javascript
相信你们都在网页中体验过图片懒加载,它应该有这样的效果:当图片进入咱们的可视区时,加载这些图片。其缘由相信你们都懂的——提升用户体验。java
那么在代码中,咱们就应该实现一下几点功能:
1.当页面加载完成时,先对可视区的图片进行加载;
2.给 scroll
及 resize
事件添加监听;
3.当上述事件触发时,对在可视区的图片进行加载,并将加载过的图片移除。git
通过上面的分析,咱们一步一步来实现图片懒加载。首先,咱们先制定一些规则:
1.须要懒加载的图片标签应该带有值为 lazyload-img
的类;
2.须要懒加载的图片标签应该带有属性 data-src
,其值为图片的连接。github
function LazyLoad() { // 将全部须要懒加载的图片缓存在 imgList 数组中 this.imgList = [].slice.call(document.querySelectorAll(".lazyload-img")); // 进行初始化操做 this.init(); }
接下来想一想咱们的 init
方法应该作些什么?图片的加载是经过事件触发实现的,因此我在初始化的方法主要作的事情就是添加事件监听。数组
把 init
方法的实现放到最后来说,接下来先来实现判断图片是否在可视区的方法 isInViewport
。浏览器
在上代码前先来说讲 getBoundingClientRect
这货,不知道你们对她了解多少。MDN上给出的定义是这样的:缓存
Element.getBoundingClientRect()方法返回元素的大小及其相对于视口的位置。函数
什么意思呢,就是调用了这个方法后,返回了一个包含元素的宽高及其相对于浏览器视口左上角的位置信息。嗯.. 没看懂:( 简单点说呢,这个方法返回了一个对象,长这样:优化
{ bottom: xx, left: xx, right: xx, top: xx, height: xx, width: xx }
若是仍是不太明白,能够直接到MDN看看。建议你们直接在控制台试试,说得再多不如动手试一试。
那了解这个方法后,有啥用?固然是用来判断图片是否在可视区咯,那咱们来看看判断的逻辑:this
LazyLoad.prototype.isInViewport = function (img) { var clientH = document.documentElement.clientHeight, // 浏览器视口高度 clientW = document.documentElement.clientWidth, // 浏览器视口宽度 imgPosOb = img.getBoundingClientRect(), // 获取img的位置信息 imgT = imgPosOb.top, imgL = imgPosOb.left, imgH = imgPosOb.height, imgW = imgPosOb.width; // 判断逻辑 // 不清楚的同窗能够在草稿纸上画个图 if( (imgT > -imgH && imgT < clientH) && (imgL > -imgW && imgL < clientW) ) { // inViewport return true; } else { return false; } }
咱们还有什么功能没实现?固然还有最重要的加载!
这一步没啥好说的,直接上代码:
// 参数 imgList 是要加载的图片列表 LazyLoad.prototype.loadImg = function (inVpImgList) { var len = inVpImgList.length; var src = ''; for (var i = 0; i < len; i++) { src = inVpImgList[i].getAttribute("data-src"); inVpImgList[i].src = src; inVpImgList[i].removeAttribute("data-src"); this.removeItem(inVpImgList[i]); } }; // 不要忘了这一步 // 把加载过的图片移除 LazyLoad.prototype.removeItem = function (img) { var idx = this.imgList.indexOf(img); if(idx > -1) { this.imgList.splice(idx, 1); } };
最后,来完成咱们的初始化方法:
LazyLoad.prototype.init = function () { var self = this; // callback函数即咱们定义的事件触发后的回调函数 function callback() { var imgInVp = []; var len = self.imgList.length; for (var i = 0; i < len; i++) { if(self.isInViewport(self.imgList[i])) { imgInVp.push(self.imgList[i]); } } self.loadImg(imgInVp); } callback(); document.addEventListener("scroll", callback, false); window.addEventListener("resize", callback, false); };
可能有哪位细心的小伙伴会发现我在 init
方法中调用了一次 callback
。让咱们再回头看看功能分析的第一点,你就明白了。那到这咱就完事了?不,还得优化一下。
咱们知道当咱们在短期内,连续地改变浏览器窗口大小或者滚动页面,会连续屡次地触发 resize
和 scroll
事件。而这是咱们能够优化的地方,这里咱们使用函数去抖,调整后的代码以下:
LazyLoad.prototype.init = function () { var self = this, timer = null; function callback() { timer && clearTimeout(timer); timer = setTimeout(function () { var imgInVp = []; var len = self.imgList.length; for (var i = 0; i < len; i++) { if(self.isInViewport(self.imgList[i])) { imgInVp.push(self.imgList[i]); } } self.loadImg(imgInVp); }, 100); } callback(); document.addEventListener("scroll", callback, false); window.addEventListener("resize", callback, false); };
至此,也算是实现了一个简单的图片懒加载库了,若有不足之处欢迎指正,你们一块儿交流交流 :)