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.
1806 lines
44 KiB
1806 lines
44 KiB
/*!
|
|
* Vue-Lazyload.js v1.3.3
|
|
* (c) 2019 Awe <hilongjw@gmail.com>
|
|
* Released under the MIT License.
|
|
*/
|
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
|
|
return typeof obj;
|
|
} : function (obj) {
|
|
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var classCallCheck = function (instance, Constructor) {
|
|
if (!(instance instanceof Constructor)) {
|
|
throw new TypeError("Cannot call a class as a function");
|
|
}
|
|
};
|
|
|
|
var createClass = function () {
|
|
function defineProperties(target, props) {
|
|
for (var i = 0; i < props.length; i++) {
|
|
var descriptor = props[i];
|
|
descriptor.enumerable = descriptor.enumerable || false;
|
|
descriptor.configurable = true;
|
|
if ("value" in descriptor) descriptor.writable = true;
|
|
Object.defineProperty(target, descriptor.key, descriptor);
|
|
}
|
|
}
|
|
|
|
return function (Constructor, protoProps, staticProps) {
|
|
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
|
if (staticProps) defineProperties(Constructor, staticProps);
|
|
return Constructor;
|
|
};
|
|
}();
|
|
|
|
/*!
|
|
* is-primitive <https://github.com/jonschlinkert/is-primitive>
|
|
*
|
|
* Copyright (c) 2014-2015, Jon Schlinkert.
|
|
* Licensed under the MIT License.
|
|
*/
|
|
|
|
// see http://jsperf.com/testing-value-is-primitive/7
|
|
|
|
var isPrimitive = function isPrimitive(value) {
|
|
return value == null || typeof value !== 'function' && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) !== 'object';
|
|
};
|
|
|
|
/*!
|
|
* assign-symbols <https://github.com/jonschlinkert/assign-symbols>
|
|
*
|
|
* Copyright (c) 2015, Jon Schlinkert.
|
|
* Licensed under the MIT License.
|
|
*/
|
|
|
|
var assignSymbols = function assignSymbols(receiver, objects) {
|
|
if (receiver === null || typeof receiver === 'undefined') {
|
|
throw new TypeError('expected first argument to be an object.');
|
|
}
|
|
|
|
if (typeof objects === 'undefined' || typeof Symbol === 'undefined') {
|
|
return receiver;
|
|
}
|
|
|
|
if (typeof Object.getOwnPropertySymbols !== 'function') {
|
|
return receiver;
|
|
}
|
|
|
|
var isEnumerable = Object.prototype.propertyIsEnumerable;
|
|
var target = Object(receiver);
|
|
var len = arguments.length,
|
|
i = 0;
|
|
|
|
while (++i < len) {
|
|
var provider = Object(arguments[i]);
|
|
var names = Object.getOwnPropertySymbols(provider);
|
|
|
|
for (var j = 0; j < names.length; j++) {
|
|
var key = names[j];
|
|
|
|
if (isEnumerable.call(provider, key)) {
|
|
target[key] = provider[key];
|
|
}
|
|
}
|
|
}
|
|
return target;
|
|
};
|
|
|
|
var toString = Object.prototype.toString;
|
|
|
|
/**
|
|
* Get the native `typeof` a value.
|
|
*
|
|
* @param {*} `val`
|
|
* @return {*} Native javascript type
|
|
*/
|
|
|
|
var kindOf = function kindOf(val) {
|
|
var type = typeof val === 'undefined' ? 'undefined' : _typeof(val);
|
|
|
|
// primitivies
|
|
if (type === 'undefined') {
|
|
return 'undefined';
|
|
}
|
|
if (val === null) {
|
|
return 'null';
|
|
}
|
|
if (val === true || val === false || val instanceof Boolean) {
|
|
return 'boolean';
|
|
}
|
|
if (type === 'string' || val instanceof String) {
|
|
return 'string';
|
|
}
|
|
if (type === 'number' || val instanceof Number) {
|
|
return 'number';
|
|
}
|
|
|
|
// functions
|
|
if (type === 'function' || val instanceof Function) {
|
|
if (typeof val.constructor.name !== 'undefined' && val.constructor.name.slice(0, 9) === 'Generator') {
|
|
return 'generatorfunction';
|
|
}
|
|
return 'function';
|
|
}
|
|
|
|
// array
|
|
if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) {
|
|
return 'array';
|
|
}
|
|
|
|
// check for instances of RegExp and Date before calling `toString`
|
|
if (val instanceof RegExp) {
|
|
return 'regexp';
|
|
}
|
|
if (val instanceof Date) {
|
|
return 'date';
|
|
}
|
|
|
|
// other objects
|
|
type = toString.call(val);
|
|
|
|
if (type === '[object RegExp]') {
|
|
return 'regexp';
|
|
}
|
|
if (type === '[object Date]') {
|
|
return 'date';
|
|
}
|
|
if (type === '[object Arguments]') {
|
|
return 'arguments';
|
|
}
|
|
if (type === '[object Error]') {
|
|
return 'error';
|
|
}
|
|
if (type === '[object Promise]') {
|
|
return 'promise';
|
|
}
|
|
|
|
// buffer
|
|
if (isBuffer(val)) {
|
|
return 'buffer';
|
|
}
|
|
|
|
// es6: Map, WeakMap, Set, WeakSet
|
|
if (type === '[object Set]') {
|
|
return 'set';
|
|
}
|
|
if (type === '[object WeakSet]') {
|
|
return 'weakset';
|
|
}
|
|
if (type === '[object Map]') {
|
|
return 'map';
|
|
}
|
|
if (type === '[object WeakMap]') {
|
|
return 'weakmap';
|
|
}
|
|
if (type === '[object Symbol]') {
|
|
return 'symbol';
|
|
}
|
|
|
|
if (type === '[object Map Iterator]') {
|
|
return 'mapiterator';
|
|
}
|
|
if (type === '[object Set Iterator]') {
|
|
return 'setiterator';
|
|
}
|
|
if (type === '[object String Iterator]') {
|
|
return 'stringiterator';
|
|
}
|
|
if (type === '[object Array Iterator]') {
|
|
return 'arrayiterator';
|
|
}
|
|
|
|
// typed arrays
|
|
if (type === '[object Int8Array]') {
|
|
return 'int8array';
|
|
}
|
|
if (type === '[object Uint8Array]') {
|
|
return 'uint8array';
|
|
}
|
|
if (type === '[object Uint8ClampedArray]') {
|
|
return 'uint8clampedarray';
|
|
}
|
|
if (type === '[object Int16Array]') {
|
|
return 'int16array';
|
|
}
|
|
if (type === '[object Uint16Array]') {
|
|
return 'uint16array';
|
|
}
|
|
if (type === '[object Int32Array]') {
|
|
return 'int32array';
|
|
}
|
|
if (type === '[object Uint32Array]') {
|
|
return 'uint32array';
|
|
}
|
|
if (type === '[object Float32Array]') {
|
|
return 'float32array';
|
|
}
|
|
if (type === '[object Float64Array]') {
|
|
return 'float64array';
|
|
}
|
|
|
|
// must be a plain object
|
|
return 'object';
|
|
};
|
|
|
|
/**
|
|
* If you need to support Safari 5-7 (8-10 yr-old browser),
|
|
* take a look at https://github.com/feross/is-buffer
|
|
*/
|
|
|
|
function isBuffer(val) {
|
|
return val.constructor && typeof val.constructor.isBuffer === 'function' && val.constructor.isBuffer(val);
|
|
}
|
|
|
|
function assign(target /*, objects*/) {
|
|
target = target || {};
|
|
var len = arguments.length,
|
|
i = 0;
|
|
if (len === 1) {
|
|
return target;
|
|
}
|
|
while (++i < len) {
|
|
var val = arguments[i];
|
|
if (isPrimitive(target)) {
|
|
target = val;
|
|
}
|
|
if (isObject$1(val)) {
|
|
extend(target, val);
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
|
|
/**
|
|
* Shallow extend
|
|
*/
|
|
|
|
function extend(target, obj) {
|
|
assignSymbols(target, obj);
|
|
|
|
for (var key in obj) {
|
|
if (key !== '__proto__' && hasOwn(obj, key)) {
|
|
var val = obj[key];
|
|
if (isObject$1(val)) {
|
|
if (kindOf(target[key]) === 'undefined' && kindOf(val) === 'function') {
|
|
target[key] = val;
|
|
}
|
|
target[key] = assign(target[key] || {}, val);
|
|
} else {
|
|
target[key] = val;
|
|
}
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
|
|
/**
|
|
* Returns true if the object is a plain object or a function.
|
|
*/
|
|
|
|
function isObject$1(obj) {
|
|
return kindOf(obj) === 'object' || kindOf(obj) === 'function';
|
|
}
|
|
|
|
/**
|
|
* Returns true if the given `key` is an own property of `obj`.
|
|
*/
|
|
|
|
function hasOwn(obj, key) {
|
|
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
}
|
|
|
|
/**
|
|
* Expose `assign`
|
|
*/
|
|
|
|
var assignDeep = assign;
|
|
|
|
var inBrowser = typeof window !== 'undefined';
|
|
var hasIntersectionObserver = checkIntersectionObserver();
|
|
|
|
function checkIntersectionObserver() {
|
|
if (inBrowser && 'IntersectionObserver' in window && 'IntersectionObserverEntry' in window && 'intersectionRatio' in window.IntersectionObserverEntry.prototype) {
|
|
// Minimal polyfill for Edge 15's lack of `isIntersecting`
|
|
// See: https://github.com/w3c/IntersectionObserver/issues/211
|
|
if (!('isIntersecting' in window.IntersectionObserverEntry.prototype)) {
|
|
Object.defineProperty(window.IntersectionObserverEntry.prototype, 'isIntersecting', {
|
|
get: function get$$1() {
|
|
return this.intersectionRatio > 0;
|
|
}
|
|
});
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
var modeType = {
|
|
event: 'event',
|
|
observer: 'observer'
|
|
|
|
// CustomEvent polyfill
|
|
};var CustomEvent = function () {
|
|
if (!inBrowser) return;
|
|
if (typeof window.CustomEvent === 'function') return window.CustomEvent;
|
|
function CustomEvent(event, params) {
|
|
params = params || { bubbles: false, cancelable: false, detail: undefined };
|
|
var evt = document.createEvent('CustomEvent');
|
|
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
|
|
return evt;
|
|
}
|
|
CustomEvent.prototype = window.Event.prototype;
|
|
return CustomEvent;
|
|
}();
|
|
|
|
function remove(arr, item) {
|
|
if (!arr.length) return;
|
|
var index = arr.indexOf(item);
|
|
if (index > -1) return arr.splice(index, 1);
|
|
}
|
|
|
|
function some(arr, fn) {
|
|
var has = false;
|
|
for (var i = 0, len = arr.length; i < len; i++) {
|
|
if (fn(arr[i])) {
|
|
has = true;
|
|
break;
|
|
}
|
|
}
|
|
return has;
|
|
}
|
|
|
|
function getBestSelectionFromSrcset(el, scale) {
|
|
if (el.tagName !== 'IMG' || !el.getAttribute('data-srcset')) return;
|
|
|
|
var options = el.getAttribute('data-srcset');
|
|
var result = [];
|
|
var container = el.parentNode;
|
|
var containerWidth = container.offsetWidth * scale;
|
|
|
|
var spaceIndex = void 0;
|
|
var tmpSrc = void 0;
|
|
var tmpWidth = void 0;
|
|
|
|
options = options.trim().split(',');
|
|
|
|
options.map(function (item) {
|
|
item = item.trim();
|
|
spaceIndex = item.lastIndexOf(' ');
|
|
if (spaceIndex === -1) {
|
|
tmpSrc = item;
|
|
tmpWidth = 999998;
|
|
} else {
|
|
tmpSrc = item.substr(0, spaceIndex);
|
|
tmpWidth = parseInt(item.substr(spaceIndex + 1, item.length - spaceIndex - 2), 10);
|
|
}
|
|
result.push([tmpWidth, tmpSrc]);
|
|
});
|
|
|
|
result.sort(function (a, b) {
|
|
if (a[0] < b[0]) {
|
|
return 1;
|
|
}
|
|
if (a[0] > b[0]) {
|
|
return -1;
|
|
}
|
|
if (a[0] === b[0]) {
|
|
if (b[1].indexOf('.webp', b[1].length - 5) !== -1) {
|
|
return 1;
|
|
}
|
|
if (a[1].indexOf('.webp', a[1].length - 5) !== -1) {
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
});
|
|
var bestSelectedSrc = '';
|
|
var tmpOption = void 0;
|
|
|
|
for (var i = 0; i < result.length; i++) {
|
|
tmpOption = result[i];
|
|
bestSelectedSrc = tmpOption[1];
|
|
var next = result[i + 1];
|
|
if (next && next[0] < containerWidth) {
|
|
bestSelectedSrc = tmpOption[1];
|
|
break;
|
|
} else if (!next) {
|
|
bestSelectedSrc = tmpOption[1];
|
|
break;
|
|
}
|
|
}
|
|
|
|
return bestSelectedSrc;
|
|
}
|
|
|
|
function find(arr, fn) {
|
|
var item = void 0;
|
|
for (var i = 0, len = arr.length; i < len; i++) {
|
|
if (fn(arr[i])) {
|
|
item = arr[i];
|
|
break;
|
|
}
|
|
}
|
|
return item;
|
|
}
|
|
|
|
var getDPR = function getDPR() {
|
|
var scale = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1;
|
|
return inBrowser ? window.devicePixelRatio || scale : scale;
|
|
};
|
|
|
|
function supportWebp() {
|
|
if (!inBrowser) return false;
|
|
|
|
var support = true;
|
|
var d = document;
|
|
|
|
try {
|
|
var el = d.createElement('object');
|
|
el.type = 'image/webp';
|
|
el.style.visibility = 'hidden';
|
|
el.innerHTML = '!';
|
|
d.body.appendChild(el);
|
|
support = !el.offsetWidth;
|
|
d.body.removeChild(el);
|
|
} catch (err) {
|
|
support = false;
|
|
}
|
|
|
|
return support;
|
|
}
|
|
|
|
function throttle(action, delay) {
|
|
var timeout = null;
|
|
var lastRun = 0;
|
|
return function () {
|
|
if (timeout) {
|
|
return;
|
|
}
|
|
var elapsed = Date.now() - lastRun;
|
|
var context = this;
|
|
var args = arguments;
|
|
var runCallback = function runCallback() {
|
|
lastRun = Date.now();
|
|
timeout = false;
|
|
action.apply(context, args);
|
|
};
|
|
if (elapsed >= delay) {
|
|
runCallback();
|
|
} else {
|
|
timeout = setTimeout(runCallback, delay);
|
|
}
|
|
};
|
|
}
|
|
|
|
function testSupportsPassive() {
|
|
if (!inBrowser) return;
|
|
var support = false;
|
|
try {
|
|
var opts = Object.defineProperty({}, 'passive', {
|
|
get: function get$$1() {
|
|
support = true;
|
|
}
|
|
});
|
|
window.addEventListener('test', null, opts);
|
|
} catch (e) {}
|
|
return support;
|
|
}
|
|
|
|
var supportsPassive = testSupportsPassive();
|
|
|
|
var _ = {
|
|
on: function on(el, type, func) {
|
|
var capture = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
|
|
if (supportsPassive) {
|
|
el.addEventListener(type, func, {
|
|
capture: capture,
|
|
passive: true
|
|
});
|
|
} else {
|
|
el.addEventListener(type, func, capture);
|
|
}
|
|
},
|
|
off: function off(el, type, func) {
|
|
var capture = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
|
|
|
|
el.removeEventListener(type, func, capture);
|
|
}
|
|
};
|
|
|
|
var loadImageAsync = function loadImageAsync(item, resolve, reject) {
|
|
var image = new Image();
|
|
if (!item || !item.src) {
|
|
var err = new Error('image src is required');
|
|
return reject(err);
|
|
}
|
|
|
|
image.src = item.src;
|
|
|
|
image.onload = function () {
|
|
resolve({
|
|
naturalHeight: image.naturalHeight,
|
|
naturalWidth: image.naturalWidth,
|
|
src: image.src
|
|
});
|
|
};
|
|
|
|
image.onerror = function (e) {
|
|
reject(e);
|
|
};
|
|
};
|
|
|
|
var style = function style(el, prop) {
|
|
return typeof getComputedStyle !== 'undefined' ? getComputedStyle(el, null).getPropertyValue(prop) : el.style[prop];
|
|
};
|
|
|
|
var overflow = function overflow(el) {
|
|
return style(el, 'overflow') + style(el, 'overflow-y') + style(el, 'overflow-x');
|
|
};
|
|
|
|
var scrollParent = function scrollParent(el) {
|
|
if (!inBrowser) return;
|
|
if (!(el instanceof HTMLElement)) {
|
|
return window;
|
|
}
|
|
|
|
var parent = el;
|
|
|
|
while (parent) {
|
|
if (parent === document.body || parent === document.documentElement) {
|
|
break;
|
|
}
|
|
|
|
if (!parent.parentNode) {
|
|
break;
|
|
}
|
|
|
|
if (/(scroll|auto)/.test(overflow(parent))) {
|
|
return parent;
|
|
}
|
|
|
|
parent = parent.parentNode;
|
|
}
|
|
|
|
return window;
|
|
};
|
|
|
|
function isObject(obj) {
|
|
return obj !== null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object';
|
|
}
|
|
|
|
function ObjectKeys(obj) {
|
|
if (!(obj instanceof Object)) return [];
|
|
if (Object.keys) {
|
|
return Object.keys(obj);
|
|
} else {
|
|
var keys = [];
|
|
for (var key in obj) {
|
|
if (obj.hasOwnProperty(key)) {
|
|
keys.push(key);
|
|
}
|
|
}
|
|
return keys;
|
|
}
|
|
}
|
|
|
|
function ArrayFrom(arrLike) {
|
|
var len = arrLike.length;
|
|
var list = [];
|
|
for (var i = 0; i < len; i++) {
|
|
list.push(arrLike[i]);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
function noop() {}
|
|
|
|
var ImageCache = function () {
|
|
function ImageCache(_ref) {
|
|
var max = _ref.max;
|
|
classCallCheck(this, ImageCache);
|
|
|
|
this.options = {
|
|
max: max || 100
|
|
};
|
|
this._caches = [];
|
|
}
|
|
|
|
createClass(ImageCache, [{
|
|
key: 'has',
|
|
value: function has(key) {
|
|
return this._caches.indexOf(key) > -1;
|
|
}
|
|
}, {
|
|
key: 'add',
|
|
value: function add(key) {
|
|
if (this.has(key)) return;
|
|
this._caches.push(key);
|
|
if (this._caches.length > this.options.max) {
|
|
this.free();
|
|
}
|
|
}
|
|
}, {
|
|
key: 'free',
|
|
value: function free() {
|
|
this._caches.shift();
|
|
}
|
|
}]);
|
|
return ImageCache;
|
|
}();
|
|
|
|
// el: {
|
|
// state,
|
|
// src,
|
|
// error,
|
|
// loading
|
|
// }
|
|
|
|
var ReactiveListener = function () {
|
|
function ReactiveListener(_ref) {
|
|
var el = _ref.el,
|
|
src = _ref.src,
|
|
error = _ref.error,
|
|
loading = _ref.loading,
|
|
bindType = _ref.bindType,
|
|
$parent = _ref.$parent,
|
|
options = _ref.options,
|
|
elRenderer = _ref.elRenderer,
|
|
imageCache = _ref.imageCache;
|
|
classCallCheck(this, ReactiveListener);
|
|
|
|
this.el = el;
|
|
this.src = src;
|
|
this.error = error;
|
|
this.loading = loading;
|
|
this.bindType = bindType;
|
|
this.attempt = 0;
|
|
|
|
this.naturalHeight = 0;
|
|
this.naturalWidth = 0;
|
|
|
|
this.options = options;
|
|
|
|
this.rect = null;
|
|
|
|
this.$parent = $parent;
|
|
this.elRenderer = elRenderer;
|
|
this._imageCache = imageCache;
|
|
this.performanceData = {
|
|
init: Date.now(),
|
|
loadStart: 0,
|
|
loadEnd: 0
|
|
};
|
|
|
|
this.filter();
|
|
this.initState();
|
|
this.render('loading', false);
|
|
}
|
|
|
|
/*
|
|
* init listener state
|
|
* @return
|
|
*/
|
|
|
|
|
|
createClass(ReactiveListener, [{
|
|
key: 'initState',
|
|
value: function initState() {
|
|
if ('dataset' in this.el) {
|
|
this.el.dataset.src = this.src;
|
|
} else {
|
|
this.el.setAttribute('data-src', this.src);
|
|
}
|
|
|
|
this.state = {
|
|
loading: false,
|
|
error: false,
|
|
loaded: false,
|
|
rendered: false
|
|
};
|
|
}
|
|
|
|
/*
|
|
* record performance
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: 'record',
|
|
value: function record(event) {
|
|
this.performanceData[event] = Date.now();
|
|
}
|
|
|
|
/*
|
|
* update image listener data
|
|
* @param {String} image uri
|
|
* @param {String} loading image uri
|
|
* @param {String} error image uri
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: 'update',
|
|
value: function update(_ref2) {
|
|
var src = _ref2.src,
|
|
loading = _ref2.loading,
|
|
error = _ref2.error;
|
|
|
|
var oldSrc = this.src;
|
|
this.src = src;
|
|
this.loading = loading;
|
|
this.error = error;
|
|
this.filter();
|
|
if (oldSrc !== this.src) {
|
|
this.attempt = 0;
|
|
this.initState();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* get el node rect
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: 'getRect',
|
|
value: function getRect() {
|
|
this.rect = this.el.getBoundingClientRect();
|
|
}
|
|
|
|
/*
|
|
* check el is in view
|
|
* @return {Boolean} el is in view
|
|
*/
|
|
|
|
}, {
|
|
key: 'checkInView',
|
|
value: function checkInView() {
|
|
this.getRect();
|
|
return this.rect.top < window.innerHeight * this.options.preLoad && this.rect.bottom > this.options.preLoadTop && this.rect.left < window.innerWidth * this.options.preLoad && this.rect.right > 0;
|
|
}
|
|
|
|
/*
|
|
* listener filter
|
|
*/
|
|
|
|
}, {
|
|
key: 'filter',
|
|
value: function filter() {
|
|
var _this = this;
|
|
|
|
ObjectKeys(this.options.filter).map(function (key) {
|
|
_this.options.filter[key](_this, _this.options);
|
|
});
|
|
}
|
|
|
|
/*
|
|
* render loading first
|
|
* @params cb:Function
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: 'renderLoading',
|
|
value: function renderLoading(cb) {
|
|
var _this2 = this;
|
|
|
|
this.state.loading = true;
|
|
loadImageAsync({
|
|
src: this.loading
|
|
}, function (data) {
|
|
_this2.render('loading', false);
|
|
_this2.state.loading = false;
|
|
cb();
|
|
}, function () {
|
|
// handler `loading image` load failed
|
|
cb();
|
|
_this2.state.loading = false;
|
|
if (!_this2.options.silent) console.warn('VueLazyload log: load failed with loading image(' + _this2.loading + ')');
|
|
});
|
|
}
|
|
|
|
/*
|
|
* try load image and render it
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: 'load',
|
|
value: function load() {
|
|
var _this3 = this;
|
|
|
|
var onFinish = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : noop;
|
|
|
|
if (this.attempt > this.options.attempt - 1 && this.state.error) {
|
|
if (!this.options.silent) console.log('VueLazyload log: ' + this.src + ' tried too more than ' + this.options.attempt + ' times');
|
|
onFinish();
|
|
return;
|
|
}
|
|
if (this.state.rendered && this.state.loaded) return;
|
|
if (this._imageCache.has(this.src)) {
|
|
this.state.loaded = true;
|
|
this.render('loaded', true);
|
|
this.state.rendered = true;
|
|
return onFinish();
|
|
}
|
|
|
|
this.renderLoading(function () {
|
|
_this3.attempt++;
|
|
|
|
_this3.options.adapter['beforeLoad'] && _this3.options.adapter['beforeLoad'](_this3, _this3.options);
|
|
_this3.record('loadStart');
|
|
|
|
loadImageAsync({
|
|
src: _this3.src
|
|
}, function (data) {
|
|
_this3.naturalHeight = data.naturalHeight;
|
|
_this3.naturalWidth = data.naturalWidth;
|
|
_this3.state.loaded = true;
|
|
_this3.state.error = false;
|
|
_this3.record('loadEnd');
|
|
_this3.render('loaded', false);
|
|
_this3.state.rendered = true;
|
|
_this3._imageCache.add(_this3.src);
|
|
onFinish();
|
|
}, function (err) {
|
|
!_this3.options.silent && console.error(err);
|
|
_this3.state.error = true;
|
|
_this3.state.loaded = false;
|
|
_this3.render('error', false);
|
|
});
|
|
});
|
|
}
|
|
|
|
/*
|
|
* render image
|
|
* @param {String} state to render // ['loading', 'src', 'error']
|
|
* @param {String} is form cache
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: 'render',
|
|
value: function render(state, cache) {
|
|
this.elRenderer(this, state, cache);
|
|
}
|
|
|
|
/*
|
|
* output performance data
|
|
* @return {Object} performance data
|
|
*/
|
|
|
|
}, {
|
|
key: 'performance',
|
|
value: function performance() {
|
|
var state = 'loading';
|
|
var time = 0;
|
|
|
|
if (this.state.loaded) {
|
|
state = 'loaded';
|
|
time = (this.performanceData.loadEnd - this.performanceData.loadStart) / 1000;
|
|
}
|
|
|
|
if (this.state.error) state = 'error';
|
|
|
|
return {
|
|
src: this.src,
|
|
state: state,
|
|
time: time
|
|
};
|
|
}
|
|
|
|
/*
|
|
* $destroy
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: '$destroy',
|
|
value: function $destroy() {
|
|
this.el = null;
|
|
this.src = null;
|
|
this.error = null;
|
|
this.loading = null;
|
|
this.bindType = null;
|
|
this.attempt = 0;
|
|
}
|
|
}]);
|
|
return ReactiveListener;
|
|
}();
|
|
|
|
var DEFAULT_URL = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
|
var DEFAULT_EVENTS = ['scroll', 'wheel', 'mousewheel', 'resize', 'animationend', 'transitionend', 'touchmove'];
|
|
var DEFAULT_OBSERVER_OPTIONS = {
|
|
rootMargin: '0px',
|
|
threshold: 0
|
|
};
|
|
|
|
var Lazy = function (Vue) {
|
|
return function () {
|
|
function Lazy(_ref) {
|
|
var preLoad = _ref.preLoad,
|
|
error = _ref.error,
|
|
throttleWait = _ref.throttleWait,
|
|
preLoadTop = _ref.preLoadTop,
|
|
dispatchEvent = _ref.dispatchEvent,
|
|
loading = _ref.loading,
|
|
attempt = _ref.attempt,
|
|
_ref$silent = _ref.silent,
|
|
silent = _ref$silent === undefined ? true : _ref$silent,
|
|
scale = _ref.scale,
|
|
listenEvents = _ref.listenEvents,
|
|
hasbind = _ref.hasbind,
|
|
filter = _ref.filter,
|
|
adapter = _ref.adapter,
|
|
observer = _ref.observer,
|
|
observerOptions = _ref.observerOptions;
|
|
classCallCheck(this, Lazy);
|
|
|
|
this.version = '1.3.3';
|
|
this.mode = modeType.event;
|
|
this.ListenerQueue = [];
|
|
this.TargetIndex = 0;
|
|
this.TargetQueue = [];
|
|
this.options = {
|
|
silent: silent,
|
|
dispatchEvent: !!dispatchEvent,
|
|
throttleWait: throttleWait || 200,
|
|
preLoad: preLoad || 1.3,
|
|
preLoadTop: preLoadTop || 0,
|
|
error: error || DEFAULT_URL,
|
|
loading: loading || DEFAULT_URL,
|
|
attempt: attempt || 3,
|
|
scale: scale || getDPR(scale),
|
|
ListenEvents: listenEvents || DEFAULT_EVENTS,
|
|
hasbind: false,
|
|
supportWebp: supportWebp(),
|
|
filter: filter || {},
|
|
adapter: adapter || {},
|
|
observer: !!observer,
|
|
observerOptions: observerOptions || DEFAULT_OBSERVER_OPTIONS
|
|
};
|
|
this._initEvent();
|
|
this._imageCache = new ImageCache({ max: 200 });
|
|
this.lazyLoadHandler = throttle(this._lazyLoadHandler.bind(this), this.options.throttleWait);
|
|
|
|
this.setMode(this.options.observer ? modeType.observer : modeType.event);
|
|
}
|
|
|
|
/**
|
|
* update config
|
|
* @param {Object} config params
|
|
* @return
|
|
*/
|
|
|
|
|
|
createClass(Lazy, [{
|
|
key: 'config',
|
|
value: function config() {
|
|
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
|
|
assignDeep(this.options, options);
|
|
}
|
|
|
|
/**
|
|
* output listener's load performance
|
|
* @return {Array}
|
|
*/
|
|
|
|
}, {
|
|
key: 'performance',
|
|
value: function performance() {
|
|
var list = [];
|
|
|
|
this.ListenerQueue.map(function (item) {
|
|
list.push(item.performance());
|
|
});
|
|
|
|
return list;
|
|
}
|
|
|
|
/*
|
|
* add lazy component to queue
|
|
* @param {Vue} vm lazy component instance
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: 'addLazyBox',
|
|
value: function addLazyBox(vm) {
|
|
this.ListenerQueue.push(vm);
|
|
if (inBrowser) {
|
|
this._addListenerTarget(window);
|
|
this._observer && this._observer.observe(vm.el);
|
|
if (vm.$el && vm.$el.parentNode) {
|
|
this._addListenerTarget(vm.$el.parentNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* add image listener to queue
|
|
* @param {DOM} el
|
|
* @param {object} binding vue directive binding
|
|
* @param {vnode} vnode vue directive vnode
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: 'add',
|
|
value: function add(el, binding, vnode) {
|
|
var _this = this;
|
|
|
|
if (some(this.ListenerQueue, function (item) {
|
|
return item.el === el;
|
|
})) {
|
|
this.update(el, binding);
|
|
return Vue.nextTick(this.lazyLoadHandler);
|
|
}
|
|
|
|
var _valueFormatter2 = this._valueFormatter(binding.value),
|
|
src = _valueFormatter2.src,
|
|
loading = _valueFormatter2.loading,
|
|
error = _valueFormatter2.error;
|
|
|
|
Vue.nextTick(function () {
|
|
src = getBestSelectionFromSrcset(el, _this.options.scale) || src;
|
|
_this._observer && _this._observer.observe(el);
|
|
|
|
var container = Object.keys(binding.modifiers)[0];
|
|
var $parent = void 0;
|
|
|
|
if (container) {
|
|
$parent = vnode.context.$refs[container];
|
|
// if there is container passed in, try ref first, then fallback to getElementById to support the original usage
|
|
$parent = $parent ? $parent.$el || $parent : document.getElementById(container);
|
|
}
|
|
|
|
if (!$parent) {
|
|
$parent = scrollParent(el);
|
|
}
|
|
|
|
var newListener = new ReactiveListener({
|
|
bindType: binding.arg,
|
|
$parent: $parent,
|
|
el: el,
|
|
loading: loading,
|
|
error: error,
|
|
src: src,
|
|
elRenderer: _this._elRenderer.bind(_this),
|
|
options: _this.options,
|
|
imageCache: _this._imageCache
|
|
});
|
|
|
|
_this.ListenerQueue.push(newListener);
|
|
|
|
if (inBrowser) {
|
|
_this._addListenerTarget(window);
|
|
_this._addListenerTarget($parent);
|
|
}
|
|
|
|
_this.lazyLoadHandler();
|
|
Vue.nextTick(function () {
|
|
return _this.lazyLoadHandler();
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* update image src
|
|
* @param {DOM} el
|
|
* @param {object} vue directive binding
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: 'update',
|
|
value: function update(el, binding, vnode) {
|
|
var _this2 = this;
|
|
|
|
var _valueFormatter3 = this._valueFormatter(binding.value),
|
|
src = _valueFormatter3.src,
|
|
loading = _valueFormatter3.loading,
|
|
error = _valueFormatter3.error;
|
|
|
|
src = getBestSelectionFromSrcset(el, this.options.scale) || src;
|
|
|
|
var exist = find(this.ListenerQueue, function (item) {
|
|
return item.el === el;
|
|
});
|
|
if (!exist) {
|
|
this.add(el, binding, vnode);
|
|
} else {
|
|
exist.update({
|
|
src: src,
|
|
loading: loading,
|
|
error: error
|
|
});
|
|
}
|
|
if (this._observer) {
|
|
this._observer.unobserve(el);
|
|
this._observer.observe(el);
|
|
}
|
|
this.lazyLoadHandler();
|
|
Vue.nextTick(function () {
|
|
return _this2.lazyLoadHandler();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* remove listener form list
|
|
* @param {DOM} el
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: 'remove',
|
|
value: function remove$$1(el) {
|
|
if (!el) return;
|
|
this._observer && this._observer.unobserve(el);
|
|
var existItem = find(this.ListenerQueue, function (item) {
|
|
return item.el === el;
|
|
});
|
|
if (existItem) {
|
|
this._removeListenerTarget(existItem.$parent);
|
|
this._removeListenerTarget(window);
|
|
remove(this.ListenerQueue, existItem);
|
|
existItem.$destroy();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* remove lazy components form list
|
|
* @param {Vue} vm Vue instance
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: 'removeComponent',
|
|
value: function removeComponent(vm) {
|
|
if (!vm) return;
|
|
remove(this.ListenerQueue, vm);
|
|
this._observer && this._observer.unobserve(vm.el);
|
|
if (vm.$parent && vm.$el.parentNode) {
|
|
this._removeListenerTarget(vm.$el.parentNode);
|
|
}
|
|
this._removeListenerTarget(window);
|
|
}
|
|
}, {
|
|
key: 'setMode',
|
|
value: function setMode(mode) {
|
|
var _this3 = this;
|
|
|
|
if (!hasIntersectionObserver && mode === modeType.observer) {
|
|
mode = modeType.event;
|
|
}
|
|
|
|
this.mode = mode; // event or observer
|
|
|
|
if (mode === modeType.event) {
|
|
if (this._observer) {
|
|
this.ListenerQueue.forEach(function (listener) {
|
|
_this3._observer.unobserve(listener.el);
|
|
});
|
|
this._observer = null;
|
|
}
|
|
|
|
this.TargetQueue.forEach(function (target) {
|
|
_this3._initListen(target.el, true);
|
|
});
|
|
} else {
|
|
this.TargetQueue.forEach(function (target) {
|
|
_this3._initListen(target.el, false);
|
|
});
|
|
this._initIntersectionObserver();
|
|
}
|
|
}
|
|
|
|
/*
|
|
*** Private functions ***
|
|
*/
|
|
|
|
/*
|
|
* add listener target
|
|
* @param {DOM} el listener target
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: '_addListenerTarget',
|
|
value: function _addListenerTarget(el) {
|
|
if (!el) return;
|
|
var target = find(this.TargetQueue, function (target) {
|
|
return target.el === el;
|
|
});
|
|
if (!target) {
|
|
target = {
|
|
el: el,
|
|
id: ++this.TargetIndex,
|
|
childrenCount: 1,
|
|
listened: true
|
|
};
|
|
this.mode === modeType.event && this._initListen(target.el, true);
|
|
this.TargetQueue.push(target);
|
|
} else {
|
|
target.childrenCount++;
|
|
}
|
|
return this.TargetIndex;
|
|
}
|
|
|
|
/*
|
|
* remove listener target or reduce target childrenCount
|
|
* @param {DOM} el or window
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: '_removeListenerTarget',
|
|
value: function _removeListenerTarget(el) {
|
|
var _this4 = this;
|
|
|
|
this.TargetQueue.forEach(function (target, index) {
|
|
if (target.el === el) {
|
|
target.childrenCount--;
|
|
if (!target.childrenCount) {
|
|
_this4._initListen(target.el, false);
|
|
_this4.TargetQueue.splice(index, 1);
|
|
target = null;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/*
|
|
* add or remove eventlistener
|
|
* @param {DOM} el DOM or Window
|
|
* @param {boolean} start flag
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: '_initListen',
|
|
value: function _initListen(el, start) {
|
|
var _this5 = this;
|
|
|
|
this.options.ListenEvents.forEach(function (evt) {
|
|
return _[start ? 'on' : 'off'](el, evt, _this5.lazyLoadHandler);
|
|
});
|
|
}
|
|
}, {
|
|
key: '_initEvent',
|
|
value: function _initEvent() {
|
|
var _this6 = this;
|
|
|
|
this.Event = {
|
|
listeners: {
|
|
loading: [],
|
|
loaded: [],
|
|
error: []
|
|
}
|
|
};
|
|
|
|
this.$on = function (event, func) {
|
|
if (!_this6.Event.listeners[event]) _this6.Event.listeners[event] = [];
|
|
_this6.Event.listeners[event].push(func);
|
|
};
|
|
|
|
this.$once = function (event, func) {
|
|
var vm = _this6;
|
|
function on() {
|
|
vm.$off(event, on);
|
|
func.apply(vm, arguments);
|
|
}
|
|
_this6.$on(event, on);
|
|
};
|
|
|
|
this.$off = function (event, func) {
|
|
if (!func) {
|
|
if (!_this6.Event.listeners[event]) return;
|
|
_this6.Event.listeners[event].length = 0;
|
|
return;
|
|
}
|
|
remove(_this6.Event.listeners[event], func);
|
|
};
|
|
|
|
this.$emit = function (event, context, inCache) {
|
|
if (!_this6.Event.listeners[event]) return;
|
|
_this6.Event.listeners[event].forEach(function (func) {
|
|
return func(context, inCache);
|
|
});
|
|
};
|
|
}
|
|
|
|
/**
|
|
* find nodes which in viewport and trigger load
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: '_lazyLoadHandler',
|
|
value: function _lazyLoadHandler() {
|
|
var _this7 = this;
|
|
|
|
var freeList = [];
|
|
this.ListenerQueue.forEach(function (listener, index) {
|
|
if (!listener.el || !listener.el.parentNode) {
|
|
freeList.push(listener);
|
|
}
|
|
var catIn = listener.checkInView();
|
|
if (!catIn) return;
|
|
listener.load();
|
|
});
|
|
freeList.forEach(function (item) {
|
|
remove(_this7.ListenerQueue, item);
|
|
item.$destroy();
|
|
});
|
|
}
|
|
/**
|
|
* init IntersectionObserver
|
|
* set mode to observer
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: '_initIntersectionObserver',
|
|
value: function _initIntersectionObserver() {
|
|
var _this8 = this;
|
|
|
|
if (!hasIntersectionObserver) return;
|
|
this._observer = new IntersectionObserver(this._observerHandler.bind(this), this.options.observerOptions);
|
|
if (this.ListenerQueue.length) {
|
|
this.ListenerQueue.forEach(function (listener) {
|
|
_this8._observer.observe(listener.el);
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* init IntersectionObserver
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: '_observerHandler',
|
|
value: function _observerHandler(entries, observer) {
|
|
var _this9 = this;
|
|
|
|
entries.forEach(function (entry) {
|
|
if (entry.isIntersecting) {
|
|
_this9.ListenerQueue.forEach(function (listener) {
|
|
if (listener.el === entry.target) {
|
|
if (listener.state.loaded) return _this9._observer.unobserve(listener.el);
|
|
listener.load();
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* set element attribute with image'url and state
|
|
* @param {object} lazyload listener object
|
|
* @param {string} state will be rendered
|
|
* @param {bool} inCache is rendered from cache
|
|
* @return
|
|
*/
|
|
|
|
}, {
|
|
key: '_elRenderer',
|
|
value: function _elRenderer(listener, state, cache) {
|
|
if (!listener.el) return;
|
|
var el = listener.el,
|
|
bindType = listener.bindType;
|
|
|
|
|
|
var src = void 0;
|
|
switch (state) {
|
|
case 'loading':
|
|
src = listener.loading;
|
|
break;
|
|
case 'error':
|
|
src = listener.error;
|
|
break;
|
|
default:
|
|
src = listener.src;
|
|
break;
|
|
}
|
|
|
|
if (bindType) {
|
|
el.style[bindType] = 'url("' + src + '")';
|
|
} else if (el.getAttribute('src') !== src) {
|
|
el.setAttribute('src', src);
|
|
}
|
|
|
|
el.setAttribute('lazy', state);
|
|
|
|
this.$emit(state, listener, cache);
|
|
this.options.adapter[state] && this.options.adapter[state](listener, this.options);
|
|
|
|
if (this.options.dispatchEvent) {
|
|
var event = new CustomEvent(state, {
|
|
detail: listener
|
|
});
|
|
el.dispatchEvent(event);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* generate loading loaded error image url
|
|
* @param {string} image's src
|
|
* @return {object} image's loading, loaded, error url
|
|
*/
|
|
|
|
}, {
|
|
key: '_valueFormatter',
|
|
value: function _valueFormatter(value) {
|
|
var src = value;
|
|
var loading = this.options.loading;
|
|
var error = this.options.error;
|
|
|
|
// value is object
|
|
if (isObject(value)) {
|
|
if (!value.src && !this.options.silent) console.error('Vue Lazyload warning: miss src with ' + value);
|
|
src = value.src;
|
|
loading = value.loading || this.options.loading;
|
|
error = value.error || this.options.error;
|
|
}
|
|
return {
|
|
src: src,
|
|
loading: loading,
|
|
error: error
|
|
};
|
|
}
|
|
}]);
|
|
return Lazy;
|
|
}();
|
|
};
|
|
|
|
var LazyComponent = (function (lazy) {
|
|
return {
|
|
props: {
|
|
tag: {
|
|
type: String,
|
|
default: 'div'
|
|
}
|
|
},
|
|
render: function render(h) {
|
|
if (this.show === false) {
|
|
return h(this.tag);
|
|
}
|
|
return h(this.tag, null, this.$slots.default);
|
|
},
|
|
data: function data() {
|
|
return {
|
|
el: null,
|
|
state: {
|
|
loaded: false
|
|
},
|
|
rect: {},
|
|
show: false
|
|
};
|
|
},
|
|
mounted: function mounted() {
|
|
this.el = this.$el;
|
|
lazy.addLazyBox(this);
|
|
lazy.lazyLoadHandler();
|
|
},
|
|
beforeDestroy: function beforeDestroy() {
|
|
lazy.removeComponent(this);
|
|
},
|
|
|
|
methods: {
|
|
getRect: function getRect() {
|
|
this.rect = this.$el.getBoundingClientRect();
|
|
},
|
|
checkInView: function checkInView() {
|
|
this.getRect();
|
|
return inBrowser && this.rect.top < window.innerHeight * lazy.options.preLoad && this.rect.bottom > 0 && this.rect.left < window.innerWidth * lazy.options.preLoad && this.rect.right > 0;
|
|
},
|
|
load: function load() {
|
|
this.show = true;
|
|
this.state.loaded = true;
|
|
this.$emit('show', this);
|
|
},
|
|
destroy: function destroy() {
|
|
return this.$destroy;
|
|
}
|
|
}
|
|
};
|
|
});
|
|
|
|
var LazyContainerMananger = function () {
|
|
function LazyContainerMananger(_ref) {
|
|
var lazy = _ref.lazy;
|
|
classCallCheck(this, LazyContainerMananger);
|
|
|
|
this.lazy = lazy;
|
|
lazy.lazyContainerMananger = this;
|
|
this._queue = [];
|
|
}
|
|
|
|
createClass(LazyContainerMananger, [{
|
|
key: 'bind',
|
|
value: function bind(el, binding, vnode) {
|
|
var container = new LazyContainer$1({ el: el, binding: binding, vnode: vnode, lazy: this.lazy });
|
|
this._queue.push(container);
|
|
}
|
|
}, {
|
|
key: 'update',
|
|
value: function update(el, binding, vnode) {
|
|
var container = find(this._queue, function (item) {
|
|
return item.el === el;
|
|
});
|
|
if (!container) return;
|
|
container.update({ el: el, binding: binding, vnode: vnode });
|
|
}
|
|
}, {
|
|
key: 'unbind',
|
|
value: function unbind(el, binding, vnode) {
|
|
var container = find(this._queue, function (item) {
|
|
return item.el === el;
|
|
});
|
|
if (!container) return;
|
|
container.clear();
|
|
remove(this._queue, container);
|
|
}
|
|
}]);
|
|
return LazyContainerMananger;
|
|
}();
|
|
|
|
var defaultOptions = {
|
|
selector: 'img'
|
|
};
|
|
|
|
var LazyContainer$1 = function () {
|
|
function LazyContainer(_ref2) {
|
|
var el = _ref2.el,
|
|
binding = _ref2.binding,
|
|
vnode = _ref2.vnode,
|
|
lazy = _ref2.lazy;
|
|
classCallCheck(this, LazyContainer);
|
|
|
|
this.el = null;
|
|
this.vnode = vnode;
|
|
this.binding = binding;
|
|
this.options = {};
|
|
this.lazy = lazy;
|
|
|
|
this._queue = [];
|
|
this.update({ el: el, binding: binding });
|
|
}
|
|
|
|
createClass(LazyContainer, [{
|
|
key: 'update',
|
|
value: function update(_ref3) {
|
|
var _this = this;
|
|
|
|
var el = _ref3.el,
|
|
binding = _ref3.binding;
|
|
|
|
this.el = el;
|
|
this.options = assignDeep({}, defaultOptions, binding.value);
|
|
|
|
var imgs = this.getImgs();
|
|
imgs.forEach(function (el) {
|
|
_this.lazy.add(el, assignDeep({}, _this.binding, {
|
|
value: {
|
|
src: 'dataset' in el ? el.dataset.src : el.getAttribute('data-src'),
|
|
error: ('dataset' in el ? el.dataset.error : el.getAttribute('data-error')) || _this.options.error,
|
|
loading: ('dataset' in el ? el.dataset.loading : el.getAttribute('data-loading')) || _this.options.loading
|
|
}
|
|
}), _this.vnode);
|
|
});
|
|
}
|
|
}, {
|
|
key: 'getImgs',
|
|
value: function getImgs() {
|
|
return ArrayFrom(this.el.querySelectorAll(this.options.selector));
|
|
}
|
|
}, {
|
|
key: 'clear',
|
|
value: function clear() {
|
|
var _this2 = this;
|
|
|
|
var imgs = this.getImgs();
|
|
imgs.forEach(function (el) {
|
|
return _this2.lazy.remove(el);
|
|
});
|
|
|
|
this.vnode = null;
|
|
this.binding = null;
|
|
this.lazy = null;
|
|
}
|
|
}]);
|
|
return LazyContainer;
|
|
}();
|
|
|
|
var LazyImage = (function (lazyManager) {
|
|
return {
|
|
props: {
|
|
src: [String, Object],
|
|
tag: {
|
|
type: String,
|
|
default: 'img'
|
|
}
|
|
},
|
|
render: function render(h) {
|
|
return h(this.tag, {
|
|
attrs: {
|
|
src: this.renderSrc
|
|
}
|
|
}, this.$slots.default);
|
|
},
|
|
data: function data() {
|
|
return {
|
|
el: null,
|
|
options: {
|
|
src: '',
|
|
error: '',
|
|
loading: '',
|
|
attempt: lazyManager.options.attempt
|
|
},
|
|
state: {
|
|
loaded: false,
|
|
error: false,
|
|
attempt: 0
|
|
},
|
|
rect: {},
|
|
renderSrc: ''
|
|
};
|
|
},
|
|
|
|
watch: {
|
|
src: function src() {
|
|
this.init();
|
|
lazyManager.addLazyBox(this);
|
|
lazyManager.lazyLoadHandler();
|
|
}
|
|
},
|
|
created: function created() {
|
|
this.init();
|
|
this.renderSrc = this.options.loading;
|
|
},
|
|
mounted: function mounted() {
|
|
this.el = this.$el;
|
|
lazyManager.addLazyBox(this);
|
|
lazyManager.lazyLoadHandler();
|
|
},
|
|
beforeDestroy: function beforeDestroy() {
|
|
lazyManager.removeComponent(this);
|
|
},
|
|
|
|
methods: {
|
|
init: function init() {
|
|
var _lazyManager$_valueFo = lazyManager._valueFormatter(this.src),
|
|
src = _lazyManager$_valueFo.src,
|
|
loading = _lazyManager$_valueFo.loading,
|
|
error = _lazyManager$_valueFo.error;
|
|
|
|
this.state.loaded = false;
|
|
this.options.src = src;
|
|
this.options.error = error;
|
|
this.options.loading = loading;
|
|
this.renderSrc = this.options.loading;
|
|
},
|
|
getRect: function getRect() {
|
|
this.rect = this.$el.getBoundingClientRect();
|
|
},
|
|
checkInView: function checkInView() {
|
|
this.getRect();
|
|
return inBrowser && this.rect.top < window.innerHeight * lazyManager.options.preLoad && this.rect.bottom > 0 && this.rect.left < window.innerWidth * lazyManager.options.preLoad && this.rect.right > 0;
|
|
},
|
|
load: function load() {
|
|
var _this = this;
|
|
|
|
var onFinish = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : noop;
|
|
|
|
if (this.state.attempt > this.options.attempt - 1 && this.state.error) {
|
|
if (!lazyManager.options.silent) console.log('VueLazyload log: ' + this.options.src + ' tried too more than ' + this.options.attempt + ' times');
|
|
onFinish();
|
|
return;
|
|
}
|
|
var src = this.options.src;
|
|
loadImageAsync({ src: src }, function (_ref) {
|
|
var src = _ref.src;
|
|
|
|
_this.renderSrc = src;
|
|
_this.state.loaded = true;
|
|
}, function (e) {
|
|
_this.state.attempt++;
|
|
_this.renderSrc = _this.options.error;
|
|
_this.state.error = true;
|
|
});
|
|
}
|
|
}
|
|
};
|
|
});
|
|
|
|
var index = {
|
|
/*
|
|
* install function
|
|
* @param {Vue} Vue
|
|
* @param {object} options lazyload options
|
|
*/
|
|
install: function install(Vue) {
|
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
|
|
var LazyClass = Lazy(Vue);
|
|
var lazy = new LazyClass(options);
|
|
var lazyContainer = new LazyContainerMananger({ lazy: lazy });
|
|
|
|
var isVue2 = Vue.version.split('.')[0] === '2';
|
|
|
|
Vue.prototype.$Lazyload = lazy;
|
|
|
|
if (options.lazyComponent) {
|
|
Vue.component('lazy-component', LazyComponent(lazy));
|
|
}
|
|
|
|
if (options.lazyImage) {
|
|
Vue.component('lazy-image', LazyImage(lazy));
|
|
}
|
|
|
|
if (isVue2) {
|
|
Vue.directive('lazy', {
|
|
bind: lazy.add.bind(lazy),
|
|
update: lazy.update.bind(lazy),
|
|
componentUpdated: lazy.lazyLoadHandler.bind(lazy),
|
|
unbind: lazy.remove.bind(lazy)
|
|
});
|
|
Vue.directive('lazy-container', {
|
|
bind: lazyContainer.bind.bind(lazyContainer),
|
|
componentUpdated: lazyContainer.update.bind(lazyContainer),
|
|
unbind: lazyContainer.unbind.bind(lazyContainer)
|
|
});
|
|
} else {
|
|
Vue.directive('lazy', {
|
|
bind: lazy.lazyLoadHandler.bind(lazy),
|
|
update: function update(newValue, oldValue) {
|
|
assignDeep(this.vm.$refs, this.vm.$els);
|
|
lazy.add(this.el, {
|
|
modifiers: this.modifiers || {},
|
|
arg: this.arg,
|
|
value: newValue,
|
|
oldValue: oldValue
|
|
}, {
|
|
context: this.vm
|
|
});
|
|
},
|
|
unbind: function unbind() {
|
|
lazy.remove(this.el);
|
|
}
|
|
});
|
|
|
|
Vue.directive('lazy-container', {
|
|
update: function update(newValue, oldValue) {
|
|
lazyContainer.update(this.el, {
|
|
modifiers: this.modifiers || {},
|
|
arg: this.arg,
|
|
value: newValue,
|
|
oldValue: oldValue
|
|
}, {
|
|
context: this.vm
|
|
});
|
|
},
|
|
unbind: function unbind() {
|
|
lazyContainer.unbind(this.el);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
export default index;
|