图片懒加载原理及实现
1、为什么要使用懒加载?
对于图片过多的页面,为了加速页面加载速度, 所以很多时候我们需要将页面内未出现在可视区域内的图片先不做加载, 等到滚动到可视区域后再去加载。 这样子对于页面加载性能上会有很大的提升,也提高了用户体验。
2、如何实现?
其实从原理上看很简单,在页面载入的时候将页面上的img标签的src指向一个小图片, 把真实地址存放在一个自定义属性中,这里我用data-src来存放,如下。
<img src="loading.gif" data-src="http://xxx.ooo.com"/>
然后通过选择器获取页面img标签并保存,开启一个定时器,遍历保存的img标签, 判断其位置是否出现在了可视区域内。如果出现在可视区域了那么就把真实的src地址给赋值上。 并且从数组中删除,避免重复判断。 那么你可能会问,如何判断是否出现在可视区域内吗? 那就是你可以获取当前img的相对于文档顶的偏移距离减去scrollTop的距离, 然后和浏览器窗口高度在进行比较,如果小于浏览器窗口则出现在了可视区域内了, 反之,则没有。
3、好的,废话不多说,上代码
window.Echo = (function (window, document, undefined) {
'use strict';
var store = [], offset, throttle, poll;
var _inView = function (el) {//计算是否出现在视区
var coords = el.getBoundingClientRect();
return ((coords.top >= 0 && coords.left >= 0 && coords.top) <= (window.innerHeight || document.documentElement.clientHeight) + parseInt(offset));
};
var _isDeal = function(el){//是否处理过
return el.getAttribute('src') === el.getAttribute('data-src');
}
var _pollImages = function () {
for (var i = store.length; i--;) {
var self = store[i];
if (!_isDeal(self) && _inView(self)) {
self.src = self.getAttribute('data-src');
store.splice(i, 1);
}
}
};
var _throttle = function () {
clearTimeout(poll);
poll = setTimeout(_pollImages, throttle);
};
var init = function (obj) {
var nodes = document.querySelectorAll('[data-src]');
var opts = obj || {};
offset = opts.offset || 0;
throttle = opts.throttle || 250;
for (var i = 0; i < nodes.length; i++) {
store.push(nodes[i]);
}
_throttle();
if (document.addEventListener) {
window.addEventListener('scroll', _throttle, false);
} else {
window.attachEvent('onscroll', _throttle);
}
};
return {
init: init,
render: _throttle
};
})(window, document);
由于移动端网络存在带宽问题,使用过程中请求的返回的数据往往做了分页,也就是说重新请求下来的img src 并不会保存在原有的store数组当中。
拓展
上面涉及到一个计算是否在视区的方法:
getBoundingClientRect() ,这个方法返回一个矩形对象,包含四个属性:left、top、right和bottom。分别表示元素各边与页面上边和左边的距离
注意:IE、Firefox3+、Opera9.5、Chrome、Safari支持,在IE中,默认坐标从(2,2)开始计算,导致最终距离比其他浏览器多出两个像素,我们需要做个兼容。
即:document.documentElement.clientTop; // 非IE为0,IE为2
document.documentElement.clientLeft; // 非IE为0,IE为2
functiong getRect (element) {
var rect = element.getBoundingClientRect();
var top = document.documentElement.clientTop;
var left= document.documentElement.clientLeft;
return{
top : rect.top - top,
bottom : rect.bottom - top,
left : rect.left - left,
right : rect.right - left
}
}