去年就开始琢磨着怎么写一个图片延迟加载的组件了,拖到了现在才终于完成了。
参数说明:
- placehold {url}占位符,用于替代当前图片的地址;
- manual {boolean} 手动模式,默认为false,即自动模式;
- dataSrc {string} 放在img标签里的属性,也是img的真实地址;
- tops {array} 相对于document的最上方高度;
- imgs {array} 需要处理的img元素;
- screenH {number} img元素加载时相对于浏览器屏幕的最小值。即tops[i] <= screenH + scrollTop时加载。 默认是当前视图高度的1.5倍。
- isHold {boolean}<private>获取screenH 在用户没有提供screenH时,自动出现。
具体的JS代码如下:
window.onload = function(){
}
function log(a){
if(window.console)window.console.log(a);
//window.console?window.console.log(a):alert(a);
}
function mix(s, o, w, pro){
if(s === undefined || o === undefined)return{};
w = w || false;
pro = pro || false;
for(var a in o){
if(typeof a == 'object') mix(s[a], o[a], w, pro);
if(w)pro? s.prototype[a] = o[a] : s[a] = o[a];
if(!w && !s.hasOwnProperty(a)) {
s[a] = o[a];
}
}
}
/**
* 图片延迟加载组件
*@param config {object}
*@attr placehold {url} 用于替换图片src
*@attr manual {boolean} default: false 手动模式,默认是自动模式
*@attr dataSrc {string} default: data-src 存放真实的图片地址
*@attr tops {array} 所有需要加载的图片相对于body的最上方高度
*@attr imgs {array} 所有需要加载的图片
*@attr screenH {number} default: 1.5倍的屏幕高度 图片距离浏览器屏幕上方高度的临界值,小于这个高度就加载。
*@attr isHold {boolean} <private> 获取screenH 在用户没有提供screenH时,自动出现。
*@Description:
* 不适合情况:有js大变动的改变body高度。
*/
function imgLoadLater(o){
var self = this;
if(!(self instanceof imgLoadLater)){
return new imgLoadLater(o);
}
config = self._config;
if(o !== undefined && !o.screenH){
//config = {};
config.screenH = self._getScreen();
config.isHold = true;
}
mix(config, o, true);
self._config = config;
//log(self._config)
self._init();
//return undefined;
}
mix(imgLoadLater , {
_config: {//配置文件
//placehold: null,
manual: false, //手动模式,默认为false 即自动默认
dataSrc: 'data-src'
//tops: [],//存放每个元素相对于document的高度值
//imgs: [],//存放每个img元素
//screenH: 0//距离浏览器当前屏幕的高度所需的距离
},
_getTop: function(elem){
// 返回元素相对于当前浏览器屏幕顶部的高度
return elem.getBoundingClientRect().top;
},
_imgLoad: function(){
var self = this,
config = self._config,
imgs = config.imgs || [],
tops = config.tops || [],
dataSrc = config.dataSrc,
l = imgs.length,
winH = config.screenH + self._getScrollTop(),
arrImgs=[],
arrTops=[];
if(l < 1) return;
for(var i=0; i < l; i++){
//log(tops[i]+ ' '+winH);
if(tops[i] <= winH){
imgs[i].src = imgs[i].getAttribute(dataSrc);
//log(i);
}else{
arrImgs.push(imgs[i]);
arrTops.push(tops[i]);
}
}
//log(arrTops);
self._config.imgs = arrImgs;
self._config.tops = arrTops;
},
_getScreen: function(){
//
return document.documentElement.clientHeight * 1.1;
},
_getScrollTop: function(){
return Math.max(document.body.scrollTop, document.documentElement.scrollTop);
},
_filterImg: function(){
var config = this._config,
tops = config.tops || [],
imgs = config.imgs || [],
dataSrc = config.dataSrc,
placehold = config.placehold,
scrollTop = this._getScrollTop(),
winH = config.screenH + scrollTop,
arrImgs = document.getElementsByTagName('img'),
isManual = config.manual,
i, len, top;
if(isManual){
if(imgs.length)arrImgs = imgs;
else{
var temp = [];
for(i=0, len= arrImgs.length; i<len; i++){
if(arrImgs[i].getAttribute(dataSrc)) temp.push(arrImgs[i]);
}
arrImgs = temp;
}
}
for(len = arrImgs.length, i = 0; i<len; i++){
top = this._getTop(arrImgs[i]) + scrollTop;
if(isManual || top > winH){
tops.push(top);
imgs.push(arrImgs[i]);
if(!isManual) arrImgs[i].setAttribute(dataSrc, arrImgs[i].src);
placehold === undefined ? arrImgs[i].src = placehold : arrImgs[i].removeAttribute('src');
}
}
this._config.imgs = imgs;
this._config.tops = tops;
this._imgLoad();
this._filterImg = function(){};
},
_addEvent: function(elem, type, fn, b){
if(elem.addEventListener){
elem.addEventListener(type, fn, b || false);
}else if(elem.attachEvent){
elem.attachEvent('on'+type, fn);
}else{
elem['on'+type] = fn;
}
},
_removeEvent: function(elem, type, fn){
if(elem.removeEventListener){
elem.removeEventListener(type, fn);
}else if(elem.detachEvent){
elem.detachEvent('on'+type, fn);
}
},
_init: function(){
var self = this;
//self._mix(config, o);
self._filterImg();
self._addEvent(window, 'scroll', loader);
self._addEvent(window, 'resize', (resizeLoader = function(){
if(self._config.isHold) self._config.screenH = self._getScreen();
setTimeout(function(){ self._imgLoad();}, 100);
}));
function loader(){
self._imgLoad();
if(self._config.imgs.length == 0){
self._removeEvent(window, 'scroll', loader);
self._removeEvent(window, 'resize', resizeLoader);
}
}
}
}, true, true);
//log(1);
yss是看过KISSY的数据延迟加载组件后,自己单独写的一个。
(注)并在KISSY的基础上进行了部分优化,主要体现在tops这个属性上,因为正常情况下,每个图片相对于最上方的高度是不变的,除非出现dom节点的改变操作。这样就节省了每次都去获取当前的img相对于当前浏览器屏幕的高度。