You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

327 lines
8.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

(function($, window, document) {
var mid = 0;
$.Lazyload = $.Class.extend({
init: function(element, options) {
var self = this;
this.container = this.element = element;
// placeholder //默认图片
this.options = $.extend({
selector: '', //查询哪些元素需要lazyload
diff: false, //距离视窗底部多少像素出发lazyload
force: false, //强制加载(不论元素是否在是视窗内)
autoDestroy: true, //元素加载完后是否自动销毁当前插件对象
duration: 100 //滑动停止多久后开始加载
}, options);
this._key = 0;
this._containerIsNotDocument = this.container.nodeType !== 9;
this._callbacks = {};
this._init();
},
_init: function() {
this._initLoadFn();
this.addElements();
this._loadFn();
$.ready(function() {
this._loadFn();
}.bind(this));
this.resume();
},
_initLoadFn: function() {
var self = this;
self._loadFn = this._buffer(function() { // 加载延迟项
if(self.options.autoDestroy && self._counter == 0 && $.isEmptyObject(self._callbacks)) {
self.destroy();
}
self._loadItems();
}, self.options.duration, self);
},
/**
*根据加载函数实现加载器
*@param {Function} load 加载函数
*@returns {Function} 加载器
*/
_createLoader: function(load) {
var value, loading, handles = [],
h;
return function(handle) {
if(!loading) {
loading = true;
load(function(v) {
value = v;
while(h = handles.shift()) {
try {
h && h.apply(null, [value]);
} catch(e) {
setTimeout(function() {
throw e;
}, 0)
}
}
})
}
if(value) {
handle && handle.apply(null, [value]);
return value;
}
handle && handles.push(handle);
return value;
}
},
_buffer: function(fn, ms, context) {
var timer;
var lastStart = 0;
var lastEnd = 0;
var ms = ms || 150;
function run() {
if(timer) {
timer.cancel();
timer = 0;
}
lastStart = $.now();
fn.apply(context || this, arguments);
lastEnd = $.now();
}
return $.extend(function() {
if(
(!lastStart) || // 从未运行过
(lastEnd >= lastStart && $.now() - lastEnd > ms) || // 上次运行成功后已经超过ms毫秒
(lastEnd < lastStart && $.now() - lastStart > ms * 8) // 上次运行或未完成后8*ms毫秒
) {
run();
} else {
if(timer) {
timer.cancel();
}
timer = $.later(run, ms, null, arguments);
}
}, {
stop: function() {
if(timer) {
timer.cancel();
timer = 0;
}
}
});
},
_getBoundingRect: function(c) {
var vh, vw, left, top;
if(c !== undefined) {
vh = c.offsetHeight;
vw = c.offsetWidth;
var offset = $.offset(c);
left = offset.left;
top = offset.top;
} else {
vh = window.innerHeight;
vw = window.innerWidth;
left = 0;
top = window.pageYOffset;
}
var diff = this.options.diff;
var diffX = diff === false ? vw : diff;
var diffX0 = 0;
var diffX1 = diffX;
var diffY = diff === false ? vh : diff;
var diffY0 = 0;
var diffY1 = diffY;
var right = left + vw;
var bottom = top + vh;
left -= diffX0;
right += diffX1;
top -= diffY0;
bottom += diffY1;
return {
left: left,
top: top,
right: right,
bottom: bottom
};
},
_cacheWidth: function(el) {
if(el._mui_lazy_width) {
return el._mui_lazy_width;
}
return el._mui_lazy_width = el.offsetWidth;
},
_cacheHeight: function(el) {
if(el._mui_lazy_height) {
return el._mui_lazy_height;
}
return el._mui_lazy_height = el.offsetHeight;
},
_isCross: function(r1, r2) {
var r = {};
r.top = Math.max(r1.top, r2.top);
r.bottom = Math.min(r1.bottom, r2.bottom);
r.left = Math.max(r1.left, r2.left);
r.right = Math.min(r1.right, r2.right);
return r.bottom >= r.top && r.right >= r.left;
},
_elementInViewport: function(elem, windowRegion, containerRegion) {
// display none or inside display none
if(!elem.offsetWidth) {
return false;
}
var elemOffset = $.offset(elem);
var inContainer = true;
var inWin;
var left = elemOffset.left;
var top = elemOffset.top;
var elemRegion = {
left: left,
top: top,
right: left + this._cacheWidth(elem),
bottom: top + this._cacheHeight(elem)
};
inWin = this._isCross(windowRegion, elemRegion);
if(inWin && containerRegion) {
inContainer = this._isCross(containerRegion, elemRegion);
}
// 确保在容器内出现
// 并且在视窗内也出现
return inContainer && inWin;
},
_loadItems: function() {
var self = this;
// container is display none
if(self._containerIsNotDocument && !self.container.offsetWidth) {
return;
}
self._windowRegion = self._getBoundingRect();
if(self._containerIsNotDocument) {
self._containerRegion = self._getBoundingRect(this.container);
}
$.each(self._callbacks, function(key, callback) {
callback && self._loadItem(key, callback);
});
},
_loadItem: function(key, callback) {
var self = this;
callback = callback || self._callbacks[key];
if(!callback) {
return true;
}
var el = callback.el;
var remove = false;
var fn = callback.fn;
if(self.options.force || self._elementInViewport(el, self._windowRegion, self._containerRegion)) {
try {
remove = fn.call(self, el, key);
} catch(e) {
setTimeout(function() {
throw e;
}, 0);
}
}
if(remove !== false) {
delete self._callbacks[key];
}
return remove;
},
addCallback: function(el, fn) {
var self = this;
var callbacks = self._callbacks;
var callback = {
el: el,
fn: fn || $.noop
};
var key = ++this._key;
callbacks[key] = callback;
// add 立即检测,防止首屏元素问题
if(self._windowRegion) {
self._loadItem(key, callback);
} else {
self.refresh();
}
},
addElements: function(elements) {
var self = this;
self._counter = self._counter || 0;
var lazyloads = [];
if(!elements && self.options.selector) {
lazyloads = self.container.querySelectorAll(self.options.selector);
} else {
$.each(elements, function(index, el) {
lazyloads = lazyloads.concat($.qsa(self.options.selector, el));
});
}
//addElements时自动初始化一次
if(self._containerIsNotDocument) {
self._containerRegion = self._getBoundingRect(self.container);
}
$.each(lazyloads, function(index, el) {
if(!el.getAttribute('data-lazyload-id')) {
if(self.addElement(el)) {
el.setAttribute('data-lazyload-id', mid++);
self.addCallback(el, self.handle);
}
}
});
},
addElement: function(el) {
return true;
},
handle: function() {
//throw new Error('需子类实现');
},
refresh: function(check) {
if(check) { //检查新的lazyload
this.addElements();
}
this._loadFn();
},
pause: function() {
var load = this._loadFn;
if(this._destroyed) {
return;
}
window.removeEventListener('scroll', load);
window.removeEventListener($.EVENT_MOVE, load);
window.removeEventListener('resize', load);
if(this._containerIsNotDocument) {
this.container.removeEventListener('scrollend', load);
this.container.removeEventListener('scroll', load);
this.container.removeEventListener($.EVENT_MOVE, load);
}
},
resume: function() {
var load = this._loadFn;
if(this._destroyed) {
return;
}
window.addEventListener('scroll', load, false);
window.addEventListener($.EVENT_MOVE, load, false);
window.addEventListener('resize', load, false);
if(this._containerIsNotDocument) {
this.container.addEventListener('scrollend', load, false);
this.container.addEventListener('scroll', load, false);
this.container.addEventListener($.EVENT_MOVE, load, false);
}
},
destroy: function() {
var self = this;
self.pause();
self._callbacks = {};
$.trigger(this.container, 'destroy', self);
self._destroyed = 1;
}
});
})(mui, window, document);