有时我们看到一些大型网站,页面如果有很多图片的时候,当你滚动到相应的行时,当前行的图片才即时加载的,这样子的话页面在打开只加可视区域的图片,而其它隐藏的图片则不加载,一定程序上加快了页面加载的速度,对于比较长的页面来说,这个方案是比较好的。可以节省带宽,加块页面加载速度!
自己最近几天也在想着怎么实现这种功能,基本思路是给每个要延迟加载的图片一个假的src地址,然后给img标签字定义一个属性就叫dynamic吧,这个属性用了保存真实图片地址。当用户拖动滚动条时触发window.onscroll事件来检测哪些元素在用户的可视范围内,在可视范围并且还未加载的我们就加载它,嗯,基本原来就这样了。自己写了一个很基础的。
我觉得比较重要的就是如何判断我们要加载的图片是否浏览器可视范围内吧,我用的是getBoundingClientRect这个函数。比如我们判断元素a是否在可视范围内,
那么我们比较a.getBoundingClientRect().top是否小于浏览器的可视高度document.documentElement.clientHeight,并且a.getBoundingClientRect().left是否小于浏览器的可视宽度document.documentElement.clientWidth,差不多这样吧,比较复杂的以后遇到了在深入吧。
还有个优化性能的问题,一般情况下,触发程序会绑定到容器的scroll事件中。但很多时候scroll会被连续触发执行,大量连续的执行会占用很多资源。为了防止无意义的连续执行,程序设置了一个_delay方法来做延时:
原理是用一个lock属性,程序运行一次后lock设为true,并用一个setTimeout延时设置它为false。在锁定(lock为true)期间,程序不会立即执行,达到延时的效果。为了保证最后一次触发程序即使在锁定期间也能完成,用了一个timer来延时这次执行。
下面是代码:
var LazyLoader={ imgs:[], delay:1000, lock :false, timer:null, loaded:0, init:function(){ var img=document.getElementsByTagName('img'); for(var i=0,l=img.length;i<l;i++){ if(img[i].getAttribute('dynamic')){ this.imgs.push(img[i]); } } return this; }, _delay: function() { clearTimeout(this.timer); var oThis = this, delay = this.delay; if ( this.lock ) { this.timer = setTimeout( function(){ oThis._delay(); }, delay ); } else { this.lock = true; oThis.play(); setTimeout( function(){ oThis.lock = false; }, delay ); } }, play:function(){ if(this.isFinish()){ this.dispose(); return }; for(var i=0,l=this.imgs.length;i<l;i++){ if(this.imgs[i]&&isvisible(this.imgs[i])){ this.imgs[i].src=this.imgs[i].getAttribute('dynamic'); this.imgs[i].removeAttribute('dynamic',''); this.imgs[i]=null; this.loaded++; } } }, isFinish: function() { return this.loaded>=this.imgs.length; }, dispose: function() { clearTimeout(this.timer); this.imgs=null; window.onscroll=null; } } window.onload=function(){ LazyLoader.init()._delay(); } window.onscroll=function(){ LazyLoader._delay(); } function isvisible(img){ return (img.getBoundingClientRect().top<document.documentElement.clientHeight)&&(img.getBoundingClientRect().left<document.documentElement.clientWidth); }