NGToolsCSharp/NGTools/Scripts/MUI/js/mui.lazyload.js

327 lines
8.0 KiB
JavaScript
Raw Normal View History

2024-09-13 08:44:13 +00:00
(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);