179 lines
5.1 KiB
JavaScript
179 lines
5.1 KiB
JavaScript
![]() |
(function () {
|
||
|
var root = (typeof self == 'object' && self.self == self && self) ||
|
||
|
(typeof global == 'object' && global.global == global && global) ||
|
||
|
this || {};
|
||
|
|
||
|
// 修复 bind 函数
|
||
|
Function.prototype.bind = Function.prototype.bind || function (context) {
|
||
|
|
||
|
if (typeof this !== "function") {
|
||
|
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
|
||
|
}
|
||
|
|
||
|
var self = this;
|
||
|
var args = Array.prototype.slice.call(arguments, 1);
|
||
|
|
||
|
var fNOP = function () { };
|
||
|
|
||
|
var fBound = function () {
|
||
|
var bindArgs = Array.prototype.slice.call(arguments);
|
||
|
self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
|
||
|
}
|
||
|
|
||
|
fNOP.prototype = this.prototype;
|
||
|
fBound.prototype = new fNOP();
|
||
|
return fBound;
|
||
|
}
|
||
|
|
||
|
var util = {
|
||
|
extend: function (target) {
|
||
|
for (var i = 1, len = arguments.length; i < len; i++) {
|
||
|
for (var prop in arguments[i]) {
|
||
|
if (arguments[i].hasOwnProperty(prop)) {
|
||
|
target[prop] = arguments[i][prop]
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return target
|
||
|
},
|
||
|
addEvent: function (elem, type, fn) {
|
||
|
if (document.addEventListener) {
|
||
|
elem.addEventListener(type, fn, false);
|
||
|
return fn;
|
||
|
} else if (document.attachEvent) {
|
||
|
var bound = function () {
|
||
|
return fn.apply(elem, arguments)
|
||
|
}
|
||
|
elem.attachEvent('on' + type, bound);
|
||
|
return bound;
|
||
|
}
|
||
|
},
|
||
|
removeEvent: function (elem, type, fn) {
|
||
|
if (document.removeEventListener) {
|
||
|
elem.removeEventListener(type, fn, false)
|
||
|
}
|
||
|
else {
|
||
|
elem.detachEvent("on" + type, fn)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function Lazy(opts) {
|
||
|
|
||
|
this.opts = util.extend({}, this.constructor.defaultOpts, opts)
|
||
|
|
||
|
this.init();
|
||
|
}
|
||
|
|
||
|
Lazy.VERSION = '1.0.0';
|
||
|
|
||
|
Lazy.defaultOpts = {
|
||
|
delay: 250,
|
||
|
useDebounce: false
|
||
|
}
|
||
|
|
||
|
var proto = Lazy.prototype;
|
||
|
|
||
|
proto.init = function () {
|
||
|
|
||
|
this.calulateView();
|
||
|
|
||
|
this.bindScrollEvent();
|
||
|
|
||
|
};
|
||
|
|
||
|
proto.calulateView = function () {
|
||
|
|
||
|
this.view = {
|
||
|
top: 0 - (parseInt(this.opts.top, 10) || 0),
|
||
|
bottom: (root.innerHeight || document.documentElement.clientHeight) + (parseInt(this.opts.bottom, 10) || 0),
|
||
|
left: 0 - (parseInt(this.opts.left, 10) || 0),
|
||
|
right: (root.innerWidth || document.documentElement.clientWidth) + (parseInt(this.opts.right, 10) || 0)
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
proto.bindScrollEvent = function () {
|
||
|
var scrollEvent = util.addEvent(root, 'scroll', this.handleLazyLoad.bind(this))
|
||
|
var loadEvent = util.addEvent(root, 'load', this.handleLazyLoad.bind(this))
|
||
|
|
||
|
this.event = {
|
||
|
scrollEvent: scrollEvent,
|
||
|
loadEvent: loadEvent
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var timer = null;
|
||
|
|
||
|
proto.handleLazyLoad = function () {
|
||
|
var self = this;
|
||
|
|
||
|
if (!this.opts.useDebounce && !!timer) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
clearTimeout(timer);
|
||
|
|
||
|
timer = setTimeout(function () {
|
||
|
timer = null;
|
||
|
self.render()
|
||
|
}, this.opts.delay);
|
||
|
};
|
||
|
|
||
|
proto.isHidden = function (element) {
|
||
|
return (element.offsetParent === null);
|
||
|
};
|
||
|
|
||
|
proto.checkInView = function (element) {
|
||
|
if (this.isHidden(element)) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
var rect = element.getBoundingClientRect();
|
||
|
|
||
|
return (rect.right >= this.view.left && rect.bottom >= this.view.top && rect.left <= this.view.right && rect.top <= this.view.bottom);
|
||
|
};
|
||
|
|
||
|
proto.render = function () {
|
||
|
var nodes = document.querySelectorAll('[data-image], [data-lazy-background]');
|
||
|
var length = nodes.length;
|
||
|
|
||
|
for (var i = 0; i < length; i++) {
|
||
|
elem = nodes[i];
|
||
|
if (this.checkInView(elem)) {
|
||
|
|
||
|
if (elem.getAttribute('data-lazy-background') !== null) {
|
||
|
elem.style.backgroundImage = 'url(' + elem.getAttribute('data-lazy-background') + ')';
|
||
|
} else if (elem.src !== (src = elem.getAttribute('data-image'))) {
|
||
|
elem.src = src;
|
||
|
}
|
||
|
|
||
|
elem.removeAttribute('data-image');
|
||
|
elem.removeAttribute('data-lazy-background');
|
||
|
|
||
|
if (this.opts.onload && typeof this.opts.onload === 'function') {
|
||
|
this.opts.onload(elem);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!length) {
|
||
|
this.unbindScrollEvent();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
proto.unbindScrollEvent = function () {
|
||
|
util.removeEvent(root, 'scroll', this.event.scrollEvent)
|
||
|
util.removeEvent(root, 'load', this.event.loadEvent)
|
||
|
};
|
||
|
|
||
|
if (typeof exports != 'undefined' && !exports.nodeType) {
|
||
|
if (typeof module != 'undefined' && !module.nodeType && module.exports) {
|
||
|
exports = module.exports = Lazy;
|
||
|
}
|
||
|
exports.Lazy = Lazy;
|
||
|
} else {
|
||
|
root.Lazy = Lazy;
|
||
|
}
|
||
|
}());
|