123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- (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);
|