vue-lazyload
Advanced tools
Comparing version 1.3.4 to 3.0.0-rc.1
@@ -0,0 +0,0 @@ module.exports = { |
13
build.js
@@ -8,2 +8,3 @@ const path = require('path') | ||
const commonjs = require('rollup-plugin-commonjs') | ||
const typescript = require('rollup-plugin-typescript') | ||
const version = process.env.VERSION || require('./package.json').version | ||
@@ -46,9 +47,11 @@ | ||
build({ | ||
input: path.resolve(__dirname, 'src/index.js'), | ||
input: path.resolve(__dirname, 'src/index.ts'), | ||
external: ['vue'], | ||
plugins: [ | ||
resolve(), | ||
commonjs(), | ||
typescript(), | ||
babel({ runtimeHelpers: true }), | ||
replace({ | ||
'__VUE_LAZYLOAD_VERSION__': JSON.stringify(version) | ||
__VUE_LAZYLOAD_VERSION__: JSON.stringify(version) | ||
}), | ||
@@ -63,8 +66,10 @@ terser() | ||
build({ | ||
input: path.resolve(__dirname, 'src/index.js'), | ||
input: path.resolve(__dirname, 'src/index.ts'), | ||
external: ['vue'], | ||
plugins: [ | ||
resolve(), | ||
commonjs(), | ||
typescript(), | ||
replace({ | ||
'__VUE_LAZYLOAD_VERSION__': JSON.stringify(version) | ||
__VUE_LAZYLOAD_VERSION__: JSON.stringify(version) | ||
}), | ||
@@ -71,0 +76,0 @@ babel({ runtimeHelpers: true }) |
{ | ||
"name": "vue-lazyload", | ||
"version": "1.3.4", | ||
"version": "3.0.0-rc.1", | ||
"description": "Vue module for lazy-loading images in your vue.js applications.", | ||
@@ -32,3 +32,3 @@ "main": "vue-lazyload.js", | ||
"last 2 versions", | ||
"not ie <= 8" | ||
"not ie < 11" | ||
], | ||
@@ -43,5 +43,5 @@ "license": "MIT", | ||
"@babel/plugin-syntax-dynamic-import": "^7.8.3", | ||
"@babel/preset-env": "^7.12.17", | ||
"@rollup/plugin-replace": "^2.3.4", | ||
"assign-deep": "^0.4.8", | ||
"@babel/preset-env": "^7.13.12", | ||
"@rollup/plugin-replace": "^2.4.2", | ||
"assign-deep": "^1.0.1", | ||
"babel-cli": "^6.26.0", | ||
@@ -54,13 +54,13 @@ "babel-core": "^6.26.3", | ||
"babel-register": "^6.26.0", | ||
"chai": "^4.3.0", | ||
"eslint": "^4.19.1", | ||
"eslint-config-standard": "^11.0.0", | ||
"chai": "^4.3.4", | ||
"eslint": "^7.23.0", | ||
"eslint-config-standard": "^16.0.2", | ||
"eslint-plugin-import": "^2.22.1", | ||
"eslint-plugin-node": "^5.2.1", | ||
"eslint-plugin-promise": "^3.8.0", | ||
"eslint-plugin-standard": "^3.1.0", | ||
"eslint-plugin-node": "^11.1.0", | ||
"eslint-plugin-promise": "^4.3.1", | ||
"eslint-plugin-standard": "^5.0.0", | ||
"jest": "^26.6.3", | ||
"jest-canvas-mock": "^2.3.1", | ||
"mocha": "^4.0.1", | ||
"rollup": "^2.39.0", | ||
"mocha": "^8.3.2", | ||
"rollup": "^2.43.1", | ||
"rollup-plugin-babel": "^2.6.1", | ||
@@ -71,5 +71,7 @@ "rollup-plugin-commonjs": "^8.4.1", | ||
"rollup-plugin-terser": "^7.0.2", | ||
"rollup-plugin-uglify": "^1.0.1", | ||
"vue": "^2.6.12" | ||
"rollup-plugin-typescript": "^1.0.1", | ||
"tslib": "^2.1.0", | ||
"typescript": "^4.1.3", | ||
"vue": "^3.0.9" | ||
} | ||
} |
@@ -0,0 +0,0 @@ # Vue-Lazyload |
@@ -1,15 +0,30 @@ | ||
import Vue from 'vue' | ||
import { mount } from '@vue/test-utils' | ||
import VueLazyload from '../src' | ||
import genLazyCore from '../src/lazy' | ||
import assert from 'assert' | ||
import { createApp, inject } from 'vue' | ||
describe('VueLazyload.js Test Suite', function () { | ||
const App = { | ||
template: '<div></div>', | ||
data () { | ||
return { | ||
Lazyload: inject('Lazyload') | ||
} | ||
} | ||
} | ||
it('install', function () { | ||
Vue.use(VueLazyload) | ||
const vm = new Vue() | ||
assert(vm.$Lazyload, 'has $Lazyload') | ||
const wrapper = mount(App, { | ||
global: { | ||
plugins: [VueLazyload] | ||
} | ||
}) | ||
assert(wrapper.vm.Lazyload.mode, 'event') | ||
}) | ||
it('_valueFormatter', function () { | ||
const LazyCore = genLazyCore(Vue) | ||
const app = createApp(App) | ||
const LazyCore = genLazyCore(app) | ||
@@ -16,0 +31,0 @@ const lazyload = new LazyCore({ |
@@ -8,6 +8,7 @@ import "./vue"; | ||
export { | ||
VueLazyloadImage, | ||
VueLazyloadOptions, | ||
VueLazyloadHandler, | ||
VueReactiveListener | ||
VueReactiveListener, | ||
loadImageAsyncOption | ||
} from "./lazyload"; | ||
@@ -1,3 +0,8 @@ | ||
import { PluginObject } from "vue"; | ||
import { App } from 'vue' | ||
type PluginFunction<T> = (Vue: App, options?: T) => void; | ||
interface PluginObject<T> { | ||
install: PluginFunction<T>; | ||
[key: string]: any; | ||
} | ||
interface IntersectionObserverInit { | ||
@@ -9,15 +14,24 @@ root?: Element | null; | ||
export interface VueLazyloadImage { | ||
export interface VueLazyloadImageOptions { | ||
src: string; | ||
error?: string; | ||
loading?: string; | ||
error: string; | ||
loading: string; | ||
attempt: number; | ||
} | ||
export interface loadImageAsyncOption { | ||
src: string; | ||
cors?: string; | ||
} | ||
export interface VueLazyloadOptions { | ||
lazyComponent?: boolean; | ||
lazyImage?: boolean; | ||
preLoad?: number; | ||
error?: string; | ||
loading?: string; | ||
cors?: string; | ||
attempt?: number; | ||
listenEvents?: string[]; | ||
supportWebp?: boolean; | ||
adapter?: any; | ||
@@ -32,5 +46,11 @@ filter?: any; | ||
scale?: number; | ||
hasbind?: boolean; | ||
} | ||
export interface Performance { | ||
init: number; | ||
loadStart: number; | ||
loadEnd: number; | ||
} | ||
export interface VueReactiveListener { | ||
@@ -49,7 +69,3 @@ el: Element; | ||
elRenderer: Function; | ||
performanceData: { | ||
init: number, | ||
loadStart: number, | ||
loadEnd: number | ||
}; | ||
performanceData: Performance; | ||
} | ||
@@ -56,0 +72,0 @@ |
@@ -0,0 +0,0 @@ import Vue from "vue"; |
@@ -0,0 +0,0 @@ { |
/*! | ||
* Vue-Lazyload.js v1.3.4 | ||
* (c) 2021 Awe <hilongjw@gmail.com> | ||
* Vue-Lazyload.js v3.0.0-alpha.0 | ||
* (c) 2022 Awe <hilongjw@gmail.com> | ||
* Released under the MIT License. | ||
*/ | ||
/*! | ||
* is-primitive <https://github.com/jonschlinkert/is-primitive> | ||
* | ||
* Copyright (c) 2014-2015, Jon Schlinkert. | ||
* Licensed under the MIT License. | ||
*/ | ||
import { nextTick, reactive, defineComponent, ref, computed, onMounted, onUnmounted, createVNode, watch } from 'vue'; | ||
// see http://jsperf.com/testing-value-is-primitive/7 | ||
function createCommonjsModule(fn, module) { | ||
return module = { exports: {} }, fn(module, module.exports), module.exports; | ||
} | ||
var isPrimitive = function isPrimitive(value) { | ||
return value == null || typeof value !== 'function' && typeof value !== 'object'; | ||
}; | ||
var assignSymbols$1 = createCommonjsModule(function (module) { | ||
var isPrimitive$1 = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
'default': isPrimitive, | ||
__moduleExports: isPrimitive | ||
}); | ||
const toString = Object.prototype.toString; | ||
const isEnumerable = Object.prototype.propertyIsEnumerable; | ||
const getSymbols = Object.getOwnPropertySymbols; | ||
/*! | ||
* assign-symbols <https://github.com/jonschlinkert/assign-symbols> | ||
* | ||
* Copyright (c) 2015, Jon Schlinkert. | ||
* Licensed under the MIT License. | ||
*/ | ||
module.exports = (target, ...args) => { | ||
if (!isObject(target)) { | ||
throw new TypeError('expected the first argument to be an object'); | ||
} | ||
var assignSymbols = function (receiver, objects) { | ||
if (receiver === null || typeof receiver === 'undefined') { | ||
throw new TypeError('expected first argument to be an object.'); | ||
} | ||
if (args.length === 0 || typeof Symbol !== 'function' || typeof getSymbols !== 'function') { | ||
return target; | ||
} | ||
if (typeof objects === 'undefined' || typeof Symbol === 'undefined') { | ||
return receiver; | ||
} | ||
for (let arg of args) { | ||
let names = getSymbols(arg); | ||
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]; | ||
for (let key of names) { | ||
if (isEnumerable.call(arg, key)) { | ||
target[key] = arg[key]; | ||
} | ||
} | ||
} | ||
return target; | ||
}; | ||
function isObject(val) { | ||
return typeof val === 'function' || toString.call(val) === '[object Object]' || Array.isArray(val); | ||
} | ||
return target; | ||
}; | ||
}); | ||
var assignSymbols$1 = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
'default': assignSymbols, | ||
__moduleExports: assignSymbols | ||
var assignSymbols$2 = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
'default': assignSymbols$1, | ||
__moduleExports: assignSymbols$1 | ||
}); | ||
var toString = Object.prototype.toString; | ||
var assignSymbols = ( assignSymbols$2 && assignSymbols$1 ) || assignSymbols$2; | ||
/** | ||
* Get the native `typeof` a value. | ||
* | ||
* @param {*} `val` | ||
* @return {*} Native javascript type | ||
*/ | ||
var assignDeep = createCommonjsModule(function (module) { | ||
var kindOf = function kindOf(val) { | ||
var type = typeof val; | ||
const toString = Object.prototype.toString; | ||
// 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'; | ||
} | ||
const isValidKey = key => { | ||
return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'; | ||
}; | ||
// functions | ||
if (type === 'function' || val instanceof Function) { | ||
if (typeof val.constructor.name !== 'undefined' && val.constructor.name.slice(0, 9) === 'Generator') { | ||
return 'generatorfunction'; | ||
const assign = module.exports = (target, ...args) => { | ||
let i = 0; | ||
if (isPrimitive(target)) target = args[i++]; | ||
if (!target) target = {}; | ||
for (; i < args.length; i++) { | ||
if (isObject(args[i])) { | ||
for (const key of Object.keys(args[i])) { | ||
if (isValidKey(key)) { | ||
if (isObject(target[key]) && isObject(args[i][key])) { | ||
assign(target[key], args[i][key]); | ||
} else { | ||
target[key] = args[i][key]; | ||
} | ||
} | ||
} | ||
assignSymbols(target, args[i]); | ||
} | ||
} | ||
return 'function'; | ||
} | ||
return target; | ||
}; | ||
// array | ||
if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { | ||
return 'array'; | ||
function isObject(val) { | ||
return typeof val === 'function' || toString.call(val) === '[object Object]'; | ||
} | ||
// check for instances of RegExp and Date before calling `toString` | ||
if (val instanceof RegExp) { | ||
return 'regexp'; | ||
function isPrimitive(val) { | ||
return typeof val === 'object' ? val === null : typeof val !== 'function'; | ||
} | ||
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); | ||
} | ||
var kindOf$1 = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
'default': kindOf, | ||
__moduleExports: kindOf | ||
}); | ||
var isPrimitive$2 = ( isPrimitive$1 && isPrimitive ) || isPrimitive$1; | ||
var assignSymbols$2 = ( assignSymbols$1 && assignSymbols ) || assignSymbols$1; | ||
var typeOf = ( kindOf$1 && kindOf ) || kindOf$1; | ||
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$2(target)) { | ||
target = val; | ||
} | ||
if (isObject(val)) { | ||
extend(target, val); | ||
} | ||
} | ||
return target; | ||
} | ||
/** | ||
* Shallow extend | ||
*/ | ||
function extend(target, obj) { | ||
assignSymbols$2(target, obj); | ||
for (var key in obj) { | ||
if (isValidKey(key) && hasOwn(obj, key)) { | ||
var val = obj[key]; | ||
if (isObject(val)) { | ||
if (typeOf(target[key]) === 'undefined' && typeOf(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(obj) { | ||
return typeOf(obj) === 'object' || typeOf(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); | ||
} | ||
/** | ||
* Returns true if the given `key` is a valid key that can be used for assigning properties. | ||
*/ | ||
function isValidKey(key) { | ||
return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'; | ||
} | ||
/** | ||
* Expose `assign` | ||
*/ | ||
var assignDeep = assign; | ||
const inBrowser = typeof window !== 'undefined' && window !== null; | ||
const 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 () { | ||
return this.intersectionRatio > 0; | ||
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 () { | ||
return this.intersectionRatio > 0; | ||
} | ||
}); | ||
} | ||
}); | ||
return true; | ||
} | ||
return true; | ||
} | ||
return false; | ||
return false; | ||
} | ||
const modeType = { | ||
event: 'event', | ||
observer: 'observer' | ||
// CustomEvent polyfill for IE | ||
};const CustomEvent = function () { | ||
if (!inBrowser) return; | ||
// not IE | ||
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; | ||
}(); | ||
event: 'event', | ||
observer: 'observer' | ||
}; | ||
function remove(arr, item) { | ||
if (!arr.length) return; | ||
const index = arr.indexOf(item); | ||
if (index > -1) return arr.splice(index, 1); | ||
if (!arr.length) return; | ||
const index = arr.indexOf(item); | ||
if (index > -1) return arr.splice(index, 1); | ||
} | ||
function some(arr, fn) { | ||
let has = false; | ||
for (let 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; | ||
let options = el.getAttribute('data-srcset'); | ||
const result = []; | ||
const container = el.parentNode; | ||
const containerWidth = container.offsetWidth * scale; | ||
let spaceIndex; | ||
let tmpSrc; | ||
let tmpWidth; | ||
options = options.trim().split(','); | ||
options.map(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); | ||
if (el.tagName !== 'IMG' || !el.getAttribute('data-srcset')) return ''; | ||
let options = el.getAttribute('data-srcset').trim().split(','); | ||
const result = []; | ||
const container = el.parentNode; | ||
const containerWidth = container.offsetWidth * scale; | ||
let spaceIndex; | ||
let tmpSrc; | ||
let tmpWidth; | ||
options.forEach(item => { | ||
item = item.trim(); | ||
spaceIndex = item.lastIndexOf(' '); | ||
if (spaceIndex === -1) { | ||
tmpSrc = item; | ||
tmpWidth = 99999; | ||
} else { | ||
tmpSrc = item.substr(0, spaceIndex); | ||
tmpWidth = parseInt(item.substr(spaceIndex + 1, item.length - spaceIndex - 2), 10); | ||
} | ||
result.push([tmpWidth, tmpSrc]); | ||
}); | ||
result.sort((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; | ||
}); | ||
let bestSelectedSrc = ''; | ||
let tmpOption; | ||
for (let i = 0; i < result.length; i++) { | ||
tmpOption = result[i]; | ||
bestSelectedSrc = tmpOption[1]; | ||
const next = result[i + 1]; | ||
if (next && next[0] < containerWidth) { | ||
bestSelectedSrc = tmpOption[1]; | ||
break; | ||
} else if (!next) { | ||
bestSelectedSrc = tmpOption[1]; | ||
break; | ||
} | ||
} | ||
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; | ||
}); | ||
let bestSelectedSrc = ''; | ||
let tmpOption; | ||
for (let i = 0; i < result.length; i++) { | ||
tmpOption = result[i]; | ||
bestSelectedSrc = tmpOption[1]; | ||
const next = result[i + 1]; | ||
if (next && next[0] < containerWidth) { | ||
bestSelectedSrc = tmpOption[1]; | ||
break; | ||
} else if (!next) { | ||
bestSelectedSrc = tmpOption[1]; | ||
break; | ||
} | ||
} | ||
return bestSelectedSrc; | ||
return bestSelectedSrc; | ||
} | ||
function find(arr, fn) { | ||
let item; | ||
for (let i = 0, len = arr.length; i < len; i++) { | ||
if (fn(arr[i])) { | ||
item = arr[i]; | ||
break; | ||
} | ||
} | ||
return item; | ||
} | ||
const getDPR = (scale = 1) => inBrowser ? window.devicePixelRatio || scale : scale; | ||
// https://developers.google.com/speed/webp/faq#how_can_i_detect_browser_support_using_javascript | ||
function supportWebp() { | ||
if (!inBrowser) return false; | ||
let support = true; | ||
try { | ||
const elem = document.createElement('canvas'); | ||
if (elem.getContext && elem.getContext('2d')) { | ||
support = elem.toDataURL('image/webp').indexOf('data:image/webp') === 0; | ||
if (!inBrowser) return false; | ||
let support = true; | ||
function checkWebpFeature(feature, callback) { | ||
const kTestImages = { | ||
lossy: 'UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA', | ||
lossless: 'UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==', | ||
alpha: 'UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==', | ||
animation: 'UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA' | ||
}; | ||
const img = new Image(); | ||
img.onload = function () { | ||
const result = img.width > 0 && img.height > 0; | ||
callback(result); | ||
}; | ||
img.onerror = function () { | ||
// eslint-disable-next-line node/no-callback-literal | ||
callback(false); | ||
}; | ||
img.src = 'data:image/webp;base64,' + kTestImages[feature]; | ||
} | ||
} catch (err) { | ||
support = false; | ||
} | ||
return support; | ||
checkWebpFeature('lossy', isSupported => { | ||
support = isSupported; | ||
}); | ||
checkWebpFeature('lossless', isSupported => { | ||
support = isSupported; | ||
}); | ||
checkWebpFeature('alpha', isSupported => { | ||
support = isSupported; | ||
}); | ||
checkWebpFeature('animation', isSupported => { | ||
support = isSupported; | ||
}); | ||
return support; | ||
} | ||
function throttle(action, delay) { | ||
let timeout = null; | ||
let movement = null; | ||
let lastRun = 0; | ||
let needRun = false; | ||
return function () { | ||
needRun = true; | ||
if (timeout) { | ||
return; | ||
} | ||
let elapsed = Date.now() - lastRun; | ||
let context = this; | ||
let args = arguments; | ||
let runCallback = function () { | ||
lastRun = Date.now(); | ||
timeout = false; | ||
action.apply(context, args); | ||
let timeout = null; | ||
let lastRun = 0; | ||
return function () { | ||
if (timeout) { | ||
return; | ||
} | ||
const elapsed = Date.now() - lastRun; | ||
// @ts-ignore | ||
const context = this; | ||
const args = arguments; | ||
const runCallback = function () { | ||
lastRun = Date.now(); | ||
timeout = false; | ||
action.apply(context, args); | ||
}; | ||
if (elapsed >= delay) { | ||
runCallback(); | ||
} else { | ||
timeout = setTimeout(runCallback, delay); | ||
} | ||
}; | ||
if (elapsed >= delay) { | ||
runCallback(); | ||
} else { | ||
timeout = setTimeout(runCallback, delay); | ||
} | ||
if (needRun) { | ||
clearTimeout(movement); | ||
movement = setTimeout(runCallback, 2 * delay); | ||
} | ||
}; | ||
} | ||
function testSupportsPassive() { | ||
if (!inBrowser) return; | ||
let support = false; | ||
try { | ||
let opts = Object.defineProperty({}, 'passive', { | ||
get: function () { | ||
support = true; | ||
} | ||
}); | ||
window.addEventListener('test', null, opts); | ||
} catch (e) {} | ||
return support; | ||
if (!inBrowser) return false; | ||
let support = false; | ||
try { | ||
const opts = Object.defineProperty({}, 'passive', { | ||
get: function () { | ||
support = true; | ||
} | ||
}); | ||
window.addEventListener('test', noop, opts); | ||
} catch (e) {} | ||
return support; | ||
} | ||
const supportsPassive = testSupportsPassive(); | ||
const _ = { | ||
on(el, type, func, capture = false) { | ||
if (supportsPassive) { | ||
el.addEventListener(type, func, { | ||
capture: capture, | ||
passive: true | ||
}); | ||
} else { | ||
el.addEventListener(type, func, capture); | ||
on(el, type, func, capture = false) { | ||
if (supportsPassive) { | ||
el.addEventListener(type, func, { | ||
capture: capture, | ||
passive: true | ||
}); | ||
} else { | ||
el.addEventListener(type, func, capture); | ||
} | ||
}, | ||
off(el, type, func, capture = false) { | ||
el.removeEventListener(type, func, capture); | ||
} | ||
}, | ||
off(el, type, func, capture = false) { | ||
el.removeEventListener(type, func, capture); | ||
} | ||
}; | ||
const loadImageAsync = (item, resolve, reject) => { | ||
let image = new Image(); | ||
if (!item || !item.src) { | ||
const err = new Error('image src is required'); | ||
return reject(err); | ||
} | ||
image.src = item.src; | ||
if (item.cors) { | ||
image.crossOrigin = item.cors; | ||
} | ||
image.onload = function () { | ||
resolve({ | ||
naturalHeight: image.naturalHeight, | ||
naturalWidth: image.naturalWidth, | ||
src: image.src | ||
}); | ||
}; | ||
image.onerror = function (e) { | ||
reject(e); | ||
}; | ||
let image = new Image(); | ||
if (!item || !item.src) { | ||
const err = new Error('image src is required'); | ||
return reject(err); | ||
} | ||
if (item.cors) { | ||
image.crossOrigin = item.cors; | ||
} | ||
image.src = item.src; | ||
image.onload = function () { | ||
resolve({ | ||
naturalHeight: image.naturalHeight, | ||
naturalWidth: image.naturalWidth, | ||
src: image.src | ||
}); | ||
image = null; | ||
}; | ||
image.onerror = function (e) { | ||
reject(e); | ||
}; | ||
}; | ||
// keyof CSSStyleDeclaration | ||
const style = (el, prop) => { | ||
return typeof getComputedStyle !== 'undefined' ? getComputedStyle(el, null).getPropertyValue(prop) : el.style[prop]; | ||
return typeof getComputedStyle !== 'undefined' ? getComputedStyle(el, null).getPropertyValue(prop) : el.style[prop]; | ||
}; | ||
const overflow = el => { | ||
return style(el, 'overflow') + style(el, 'overflow-y') + style(el, 'overflow-x'); | ||
return style(el, 'overflow') + style(el, 'overflowY') + style(el, 'overflowX'); | ||
}; | ||
const scrollParent = el => { | ||
if (!inBrowser) return; | ||
if (!(el instanceof HTMLElement)) { | ||
return window; | ||
} | ||
let parent = el; | ||
while (parent) { | ||
if (parent === document.body || parent === document.documentElement) { | ||
break; | ||
if (!inBrowser) return; | ||
if (!(el instanceof Element)) { | ||
return window; | ||
} | ||
if (!parent.parentNode) { | ||
break; | ||
let 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; | ||
} | ||
if (/(scroll|auto)/.test(overflow(parent))) { | ||
return parent; | ||
} | ||
parent = parent.parentNode; | ||
} | ||
return window; | ||
return window; | ||
}; | ||
function isObject$1(obj) { | ||
return obj !== null && typeof obj === 'object'; | ||
} | ||
function ObjectKeys(obj) { | ||
if (!(obj instanceof Object)) return []; | ||
if (Object.keys) { | ||
return Object.keys(obj); | ||
} else { | ||
let keys = []; | ||
for (let key in obj) { | ||
if (obj.hasOwnProperty(key)) { | ||
keys.push(key); | ||
} | ||
} | ||
return keys; | ||
} | ||
} | ||
function ArrayFrom(arrLike) { | ||
let len = arrLike.length; | ||
const list = []; | ||
for (let i = 0; i < len; i++) { | ||
list.push(arrLike[i]); | ||
} | ||
return list; | ||
} | ||
function noop() {} | ||
class ImageCache { | ||
constructor({ max }) { | ||
this.options = { | ||
max: max || 100 | ||
}; | ||
this._caches = []; | ||
} | ||
has(key) { | ||
return this._caches.indexOf(key) > -1; | ||
} | ||
add(key) { | ||
if (this.has(key)) return; | ||
this._caches.push(key); | ||
if (this._caches.length > this.options.max) { | ||
this.free(); | ||
constructor(max) { | ||
this.max = max || 100; | ||
this._caches = []; | ||
} | ||
} | ||
free() { | ||
this._caches.shift(); | ||
} | ||
has(key) { | ||
return this._caches.indexOf(key) > -1; | ||
} | ||
add(key) { | ||
if (this.has(key)) return; | ||
this._caches.push(key); | ||
if (this._caches.length > this.max) { | ||
this.free(); | ||
} | ||
} | ||
free() { | ||
this._caches.shift(); | ||
} | ||
} | ||
@@ -635,218 +336,194 @@ | ||
// } | ||
class ReactiveListener { | ||
constructor({ el, src, error, loading, bindType, $parent, options, cors, elRenderer, imageCache }) { | ||
this.el = el; | ||
this.src = src; | ||
this.error = error; | ||
this.loading = loading; | ||
this.bindType = bindType; | ||
this.attempt = 0; | ||
this.cors = cors; | ||
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 | ||
*/ | ||
initState() { | ||
if ('dataset' in this.el) { | ||
this.el.dataset.src = this.src; | ||
} else { | ||
this.el.setAttribute('data-src', this.src); | ||
constructor(el, src, error, loading, bindType, $parent, options, cors, elRenderer, imageCache) { | ||
this.el = el; | ||
this.src = src; | ||
this.error = error; | ||
this.loading = loading; | ||
this.bindType = bindType; | ||
this.attempt = 0; | ||
this.cors = cors; | ||
this.naturalHeight = 0; | ||
this.naturalWidth = 0; | ||
this.options = options; | ||
this.rect = {}; | ||
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); | ||
} | ||
this.state = { | ||
loading: false, | ||
error: false, | ||
loaded: false, | ||
rendered: false | ||
}; | ||
} | ||
/* | ||
* record performance | ||
* @return | ||
*/ | ||
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 | ||
*/ | ||
update({ src, loading, error }) { | ||
const oldSrc = this.src; | ||
this.src = src; | ||
this.loading = loading; | ||
this.error = error; | ||
this.filter(); | ||
if (oldSrc !== this.src) { | ||
this.attempt = 0; | ||
this.initState(); | ||
/* | ||
* init listener state | ||
* @return | ||
*/ | ||
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 | ||
}; | ||
} | ||
} | ||
/* | ||
* get el node rect | ||
* @return | ||
*/ | ||
getRect() { | ||
this.rect = this.el.getBoundingClientRect(); | ||
} | ||
/* | ||
* check el is in view | ||
* @return {Boolean} el is in view | ||
*/ | ||
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 | ||
*/ | ||
filter() { | ||
ObjectKeys(this.options.filter).map(key => { | ||
this.options.filter[key](this, this.options); | ||
}); | ||
} | ||
/* | ||
* render loading first | ||
* @params cb:Function | ||
* @return | ||
*/ | ||
renderLoading(cb) { | ||
this.state.loading = true; | ||
loadImageAsync({ | ||
src: this.loading, | ||
cors: this.cors | ||
}, data => { | ||
this.render('loading', false); | ||
this.state.loading = false; | ||
cb(); | ||
}, () => { | ||
// handler `loading image` load failed | ||
cb(); | ||
this.state.loading = false; | ||
if (!this.options.silent) console.warn(`VueLazyload log: load failed with loading image(${this.loading})`); | ||
}); | ||
} | ||
/* | ||
* try load image and render it | ||
* @return | ||
*/ | ||
load(onFinish = 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; | ||
/* | ||
* record performance | ||
* @return | ||
*/ | ||
record(event) { | ||
this.performanceData[event] = Date.now(); | ||
} | ||
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(); | ||
/* | ||
* update image listener data | ||
* @param {String} image uri | ||
* @param {String} loading image uri | ||
* @param {String} error image uri | ||
* @return | ||
*/ | ||
update(option) { | ||
const oldSrc = this.src; | ||
this.src = option.src; | ||
this.loading = option.loading; | ||
this.error = option.error; | ||
this.filter(); | ||
if (oldSrc !== this.src) { | ||
this.attempt = 0; | ||
this.initState(); | ||
} | ||
} | ||
this.renderLoading(() => { | ||
this.attempt++; | ||
this.options.adapter['beforeLoad'] && this.options.adapter['beforeLoad'](this, this.options); | ||
this.record('loadStart'); | ||
loadImageAsync({ | ||
src: this.src, | ||
cors: this.cors | ||
}, data => { | ||
this.naturalHeight = data.naturalHeight; | ||
this.naturalWidth = data.naturalWidth; | ||
this.state.loaded = true; | ||
this.state.error = false; | ||
this.record('loadEnd'); | ||
this.render('loaded', false); | ||
this.state.rendered = true; | ||
this._imageCache.add(this.src); | ||
onFinish(); | ||
}, err => { | ||
!this.options.silent && console.error(err); | ||
this.state.error = true; | ||
this.state.loaded = false; | ||
this.render('error', false); | ||
}); | ||
}); | ||
} | ||
/* | ||
* render image | ||
* @param {String} state to render // ['loading', 'src', 'error'] | ||
* @param {String} is form cache | ||
* @return | ||
*/ | ||
render(state, cache) { | ||
this.elRenderer(this, state, cache); | ||
} | ||
/* | ||
* output performance data | ||
* @return {Object} performance data | ||
*/ | ||
performance() { | ||
let state = 'loading'; | ||
let time = 0; | ||
if (this.state.loaded) { | ||
state = 'loaded'; | ||
time = (this.performanceData.loadEnd - this.performanceData.loadStart) / 1000; | ||
/* | ||
* get el node rect | ||
* @return | ||
*/ | ||
getRect() { | ||
this.rect = this.el.getBoundingClientRect(); | ||
} | ||
if (this.state.error) state = 'error'; | ||
return { | ||
src: this.src, | ||
state, | ||
time | ||
}; | ||
} | ||
/* | ||
* $destroy | ||
* @return | ||
*/ | ||
$destroy() { | ||
this.el = null; | ||
this.src = null; | ||
this.error = null; | ||
this.loading = null; | ||
this.bindType = null; | ||
this.attempt = 0; | ||
} | ||
/* | ||
* check el is in view | ||
* @return {Boolean} el is in view | ||
*/ | ||
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 | ||
*/ | ||
filter() { | ||
for (const key in this.options.filter) { | ||
this.options.filter[key](this, this.options); | ||
} | ||
} | ||
/* | ||
* render loading first | ||
* @params cb:Function | ||
* @return | ||
*/ | ||
renderLoading(cb) { | ||
this.state.loading = true; | ||
loadImageAsync({ | ||
src: this.loading, | ||
cors: this.cors | ||
}, () => { | ||
this.render('loading', false); | ||
this.state.loading = false; | ||
cb(); | ||
}, () => { | ||
// handler `loading image` load failed | ||
cb(); | ||
this.state.loading = false; | ||
if (!this.options.silent) console.warn(`VueLazyload log: load failed with loading image(${this.loading})`); | ||
}); | ||
} | ||
/* | ||
* try load image and render it | ||
* @return | ||
*/ | ||
load(onFinish = 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(() => { | ||
this.attempt++; | ||
this.options.adapter.beforeLoad && this.options.adapter.beforeLoad(this, this.options); | ||
this.record('loadStart'); | ||
loadImageAsync({ | ||
src: this.src, | ||
cors: this.cors | ||
}, data => { | ||
this.naturalHeight = data.naturalHeight; | ||
this.naturalWidth = data.naturalWidth; | ||
this.state.loaded = true; | ||
this.state.error = false; | ||
this.record('loadEnd'); | ||
this.render('loaded', false); | ||
this.state.rendered = true; | ||
this._imageCache.add(this.src); | ||
onFinish(); | ||
}, err => { | ||
!this.options.silent && console.error(err); | ||
this.state.error = true; | ||
this.state.loaded = false; | ||
this.render('error', false); | ||
}); | ||
}); | ||
} | ||
/* | ||
* render image | ||
* @param {String} state to render // ['loading', 'src', 'error'] | ||
* @param {String} is form cache | ||
* @return | ||
*/ | ||
render(state, cache) { | ||
this.elRenderer(this, state, cache); | ||
} | ||
/* | ||
* output performance data | ||
* @return {Object} performance data | ||
*/ | ||
performance() { | ||
let state = 'loading'; | ||
let 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, | ||
time | ||
}; | ||
} | ||
/* | ||
* $destroy | ||
* @return | ||
*/ | ||
$destroy() { | ||
this.el = null; | ||
this.src = ''; | ||
this.error = null; | ||
this.loading = ''; | ||
this.bindType = null; | ||
this.attempt = 0; | ||
} | ||
} | ||
@@ -857,49 +534,36 @@ | ||
const DEFAULT_OBSERVER_OPTIONS = { | ||
rootMargin: '0px', | ||
threshold: 0 | ||
rootMargin: '0px', | ||
threshold: 0 | ||
}; | ||
function Lazy(Vue) { | ||
return class Lazy { | ||
constructor({ preLoad, error, throttleWait, preLoadTop, dispatchEvent, loading, attempt, silent = true, scale, listenEvents, hasbind, filter, adapter, observer, observerOptions }) { | ||
this.version = '"1.3.4"'; | ||
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); | ||
class Lazy { | ||
constructor({ preLoad, error, throttleWait, preLoadTop, dispatchEvent, loading, attempt, silent = true, scale, listenEvents, filter, adapter, observer, observerOptions }) { | ||
this.version = '"3.0.0-alpha.0"'; | ||
this.lazyContainerMananger = null; | ||
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, | ||
supportWebp: supportWebp(), | ||
filter: filter || {}, | ||
adapter: adapter || {}, | ||
observer: !!observer, | ||
observerOptions: observerOptions || DEFAULT_OBSERVER_OPTIONS | ||
}; | ||
this._initEvent(); | ||
this._imageCache = new ImageCache(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 | ||
*/ | ||
config(options = {}) { | ||
assignDeep(this.options, options); | ||
} | ||
/** | ||
* output listener's load performance | ||
@@ -909,11 +573,6 @@ * @return {Array} | ||
performance() { | ||
let list = []; | ||
this.ListenerQueue.map(item => { | ||
list.push(item.performance()); | ||
}); | ||
return list; | ||
const list = []; | ||
this.ListenerQueue.map(item => list.push(item.performance())); | ||
return list; | ||
} | ||
/* | ||
@@ -925,12 +584,11 @@ * add lazy component to queue | ||
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); | ||
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); | ||
} | ||
} | ||
} | ||
} | ||
/* | ||
@@ -944,51 +602,29 @@ * add image listener to queue | ||
add(el, binding, vnode) { | ||
if (some(this.ListenerQueue, item => item.el === el)) { | ||
this.update(el, binding); | ||
return Vue.nextTick(this.lazyLoadHandler); | ||
} | ||
let { src, loading, error, cors } = this._valueFormatter(binding.value); | ||
Vue.nextTick(() => { | ||
src = getBestSelectionFromSrcset(el, this.options.scale) || src; | ||
this._observer && this._observer.observe(el); | ||
const container = Object.keys(binding.modifiers)[0]; | ||
let $parent; | ||
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 (this.ListenerQueue.some(item => item.el === el)) { | ||
this.update(el, binding); | ||
return nextTick(this.lazyLoadHandler); | ||
} | ||
if (!$parent) { | ||
$parent = scrollParent(el); | ||
} | ||
const newListener = new ReactiveListener({ | ||
bindType: binding.arg, | ||
$parent, | ||
el, | ||
loading, | ||
error, | ||
src, | ||
cors, | ||
elRenderer: this._elRenderer.bind(this), | ||
options: this.options, | ||
imageCache: this._imageCache | ||
let { src, loading, error, cors } = this._valueFormatter(binding.value); | ||
nextTick(() => { | ||
src = getBestSelectionFromSrcset(el, this.options.scale) || src; | ||
this._observer && this._observer.observe(el); | ||
const container = Object.keys(binding.modifiers)[0]; | ||
let $parent; | ||
if (container) { | ||
$parent = binding.instance.$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); | ||
} | ||
const newListener = new ReactiveListener(el, src, error, loading, binding.arg, $parent, this.options, cors, this._elRenderer.bind(this), this._imageCache); | ||
this.ListenerQueue.push(newListener); | ||
if (inBrowser) { | ||
this._addListenerTarget(window); | ||
this._addListenerTarget($parent); | ||
} | ||
nextTick(this.lazyLoadHandler); | ||
}); | ||
this.ListenerQueue.push(newListener); | ||
if (inBrowser) { | ||
this._addListenerTarget(window); | ||
this._addListenerTarget($parent); | ||
} | ||
this.lazyLoadHandler(); | ||
Vue.nextTick(() => this.lazyLoadHandler()); | ||
}); | ||
} | ||
/** | ||
@@ -1001,23 +637,20 @@ * update image src | ||
update(el, binding, vnode) { | ||
let { src, loading, error } = this._valueFormatter(binding.value); | ||
src = getBestSelectionFromSrcset(el, this.options.scale) || src; | ||
const exist = find(this.ListenerQueue, item => item.el === el); | ||
if (!exist) { | ||
this.add(el, binding, vnode); | ||
} else { | ||
exist.update({ | ||
src, | ||
loading, | ||
error | ||
}); | ||
} | ||
if (this._observer) { | ||
this._observer.unobserve(el); | ||
this._observer.observe(el); | ||
} | ||
this.lazyLoadHandler(); | ||
Vue.nextTick(() => this.lazyLoadHandler()); | ||
let { src, loading, error } = this._valueFormatter(binding.value); | ||
src = getBestSelectionFromSrcset(el, this.options.scale) || src; | ||
const exist = this.ListenerQueue.find(item => item.el === el); | ||
if (!exist) { | ||
this.add(el, binding, vnode); | ||
} else { | ||
exist.update({ | ||
src, | ||
loading, | ||
error | ||
}); | ||
} | ||
if (this._observer) { | ||
this._observer.unobserve(el); | ||
this._observer.observe(el); | ||
} | ||
nextTick(this.lazyLoadHandler); | ||
} | ||
/** | ||
@@ -1029,13 +662,12 @@ * remove listener form list | ||
remove(el) { | ||
if (!el) return; | ||
this._observer && this._observer.unobserve(el); | ||
const existItem = find(this.ListenerQueue, item => item.el === el); | ||
if (existItem) { | ||
this._removeListenerTarget(existItem.$parent); | ||
this._removeListenerTarget(window); | ||
remove(this.ListenerQueue, existItem); | ||
existItem.$destroy(); | ||
} | ||
if (!el) return; | ||
this._observer && this._observer.unobserve(el); | ||
const existItem = this.ListenerQueue.find(item => item.el === el); | ||
if (existItem) { | ||
this._removeListenerTarget(existItem.$parent); | ||
this._removeListenerTarget(window); | ||
remove(this.ListenerQueue, existItem); | ||
existItem.$destroy && existItem.$destroy(); | ||
} | ||
} | ||
/* | ||
@@ -1047,41 +679,35 @@ * remove lazy components form list | ||
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); | ||
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); | ||
} | ||
setMode(mode) { | ||
if (!hasIntersectionObserver && mode === modeType.observer) { | ||
mode = modeType.event; | ||
} | ||
this.mode = mode; // event or observer | ||
if (mode === modeType.event) { | ||
if (this._observer) { | ||
this.ListenerQueue.forEach(listener => { | ||
this._observer.unobserve(listener.el); | ||
}); | ||
this._observer = null; | ||
if (!hasIntersectionObserver && mode === modeType.observer) { | ||
mode = modeType.event; | ||
} | ||
this.TargetQueue.forEach(target => { | ||
this._initListen(target.el, true); | ||
}); | ||
} else { | ||
this.TargetQueue.forEach(target => { | ||
this._initListen(target.el, false); | ||
}); | ||
this._initIntersectionObserver(); | ||
} | ||
this.mode = mode; // event or observer | ||
if (mode === modeType.event) { | ||
if (this._observer) { | ||
this.ListenerQueue.forEach(listener => { | ||
this._observer.unobserve(listener.el); | ||
}); | ||
this._observer = null; | ||
} | ||
this.TargetQueue.forEach(target => { | ||
this._initListen(target.el, true); | ||
}); | ||
} else { | ||
this.TargetQueue.forEach(target => { | ||
this._initListen(target.el, false); | ||
}); | ||
this._initIntersectionObserver(); | ||
} | ||
} | ||
/* | ||
*** Private functions *** | ||
*/ | ||
/* | ||
@@ -1093,19 +719,18 @@ * add listener target | ||
_addListenerTarget(el) { | ||
if (!el) return; | ||
let target = find(this.TargetQueue, target => 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; | ||
if (!el) return; | ||
let target = this.TargetQueue.find(target => 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; | ||
} | ||
/* | ||
@@ -1117,14 +742,13 @@ * remove listener target or reduce target childrenCount | ||
_removeListenerTarget(el) { | ||
this.TargetQueue.forEach((target, index) => { | ||
if (target.el === el) { | ||
target.childrenCount--; | ||
if (!target.childrenCount) { | ||
this._initListen(target.el, false); | ||
this.TargetQueue.splice(index, 1); | ||
target = null; | ||
} | ||
} | ||
}); | ||
this.TargetQueue.forEach((target, index) => { | ||
if (target.el === el) { | ||
target.childrenCount--; | ||
if (!target.childrenCount) { | ||
this._initListen(target.el, false); | ||
this.TargetQueue.splice(index, 1); | ||
target = null; | ||
} | ||
} | ||
}); | ||
} | ||
/* | ||
@@ -1137,43 +761,37 @@ * add or remove eventlistener | ||
_initListen(el, start) { | ||
this.options.ListenEvents.forEach(evt => _[start ? 'on' : 'off'](el, evt, this.lazyLoadHandler)); | ||
this.options.listenEvents.forEach(evt => _[start ? 'on' : 'off'](el, evt, this.lazyLoadHandler)); | ||
} | ||
_initEvent() { | ||
this.Event = { | ||
listeners: { | ||
loading: [], | ||
loaded: [], | ||
error: [] | ||
} | ||
}; | ||
this.$on = (event, func) => { | ||
if (!this.Event.listeners[event]) this.Event.listeners[event] = []; | ||
this.Event.listeners[event].push(func); | ||
}; | ||
this.$once = (event, func) => { | ||
const vm = this; | ||
function on() { | ||
vm.$off(event, on); | ||
func.apply(vm, arguments); | ||
} | ||
this.$on(event, on); | ||
}; | ||
this.$off = (event, func) => { | ||
if (!func) { | ||
if (!this.Event.listeners[event]) return; | ||
this.Event.listeners[event].length = 0; | ||
return; | ||
} | ||
remove(this.Event.listeners[event], func); | ||
}; | ||
this.$emit = (event, context, inCache) => { | ||
if (!this.Event.listeners[event]) return; | ||
this.Event.listeners[event].forEach(func => func(context, inCache)); | ||
}; | ||
this.Event = { | ||
listeners: { | ||
loading: [], | ||
loaded: [], | ||
error: [] | ||
} | ||
}; | ||
this.$on = (event, func) => { | ||
if (!this.Event.listeners[event]) this.Event.listeners[event] = []; | ||
this.Event.listeners[event].push(func); | ||
}; | ||
this.$once = (event, func) => { | ||
const vm = this; | ||
function on() { | ||
vm.$off(event, on); | ||
func.apply(vm, arguments); | ||
} | ||
this.$on(event, on); | ||
}; | ||
this.$off = (event, func) => { | ||
if (!func) { | ||
if (!this.Event.listeners[event]) return; | ||
this.Event.listeners[event].length = 0; | ||
return; | ||
} | ||
remove(this.Event.listeners[event], func); | ||
}; | ||
this.$emit = (event, context, inCache) => { | ||
if (!this.Event.listeners[event]) return; | ||
this.Event.listeners[event].forEach(func => func(context, inCache)); | ||
}; | ||
} | ||
/** | ||
@@ -1184,15 +802,15 @@ * find nodes which in viewport and trigger load | ||
_lazyLoadHandler() { | ||
const freeList = []; | ||
this.ListenerQueue.forEach((listener, index) => { | ||
if (!listener.el || !listener.el.parentNode) { | ||
freeList.push(listener); | ||
} | ||
const catIn = listener.checkInView(); | ||
if (!catIn) return; | ||
listener.load(); | ||
}); | ||
freeList.forEach(item => { | ||
remove(this.ListenerQueue, item); | ||
item.$destroy(); | ||
}); | ||
const freeList = []; | ||
this.ListenerQueue.forEach((listener, index) => { | ||
if (!listener.el || !listener.el.parentNode || listener.state.loaded) { | ||
freeList.push(listener); | ||
} | ||
const catIn = listener.checkInView(); | ||
if (!catIn) return; | ||
if (!listener.state.loaded) listener.load(); | ||
}); | ||
freeList.forEach(item => { | ||
remove(this.ListenerQueue, item); | ||
item.$destroy && item.$destroy(); | ||
}); | ||
} | ||
@@ -1205,32 +823,31 @@ /** | ||
_initIntersectionObserver() { | ||
if (!hasIntersectionObserver) return; | ||
this._observer = new IntersectionObserver(this._observerHandler.bind(this), this.options.observerOptions); | ||
if (this.ListenerQueue.length) { | ||
this.ListenerQueue.forEach(listener => { | ||
this._observer.observe(listener.el); | ||
}); | ||
} | ||
if (!hasIntersectionObserver) return; | ||
this._observer = new IntersectionObserver(this._observerHandler.bind(this), this.options.observerOptions); | ||
if (this.ListenerQueue.length) { | ||
this.ListenerQueue.forEach(listener => { | ||
this._observer.observe(listener.el); | ||
}); | ||
} | ||
} | ||
/** | ||
* init IntersectionObserver | ||
* @param {Array<IntersectionObserverEntry>} entries | ||
* @return | ||
*/ | ||
_observerHandler(entries, observer) { | ||
entries.forEach(entry => { | ||
if (entry.isIntersecting) { | ||
this.ListenerQueue.forEach(listener => { | ||
if (listener.el === entry.target) { | ||
if (listener.state.loaded) return this._observer.unobserve(listener.el); | ||
listener.load(); | ||
_observerHandler(entries) { | ||
entries.forEach(entry => { | ||
if (entry.isIntersecting) { | ||
this.ListenerQueue.forEach(listener => { | ||
if (listener.el === entry.target) { | ||
if (listener.state.loaded) return this._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 {ReactiveListener} lazyload listener object | ||
* @param {TeventType} state will be rendered | ||
* @param {bool} inCache is rendered from cache | ||
@@ -1240,423 +857,285 @@ * @return | ||
_elRenderer(listener, state, cache) { | ||
if (!listener.el) return; | ||
const { el, bindType } = listener; | ||
let src; | ||
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) { | ||
const event = new CustomEvent(state, { | ||
detail: listener | ||
}); | ||
el.dispatchEvent(event); | ||
} | ||
if (!listener.el) return; | ||
const { el, bindType } = listener; | ||
let src; | ||
switch (state) { | ||
case 'loading': | ||
src = listener.loading; | ||
break; | ||
case 'error': | ||
src = listener.error; | ||
break; | ||
default: | ||
src = listener.src; | ||
break; | ||
} | ||
if (bindType) { | ||
// @ts-ignore | ||
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) { | ||
const 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 | ||
*/ | ||
_valueFormatter(value) { | ||
let src = value; | ||
let loading = this.options.loading; | ||
let error = this.options.error; | ||
// value is object | ||
if (isObject$1(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, | ||
loading, | ||
error | ||
}; | ||
if (typeof value === 'object') { | ||
if (!value.src && !this.options.silent) console.error('Vue Lazyload warning: miss src with ' + value); | ||
return { | ||
src: value.src, | ||
loading: value.loading || this.options.loading, | ||
error: value.error || this.options.error, | ||
cors: this.options.cors | ||
}; | ||
} | ||
return { | ||
src: value, | ||
loading: this.options.loading, | ||
error: this.options.error, | ||
cors: this.options.cors | ||
}; | ||
} | ||
}; | ||
} | ||
Lazy.install = (Vue, options = {}) => { | ||
const LazyClass = Lazy(Vue); | ||
const lazy = new LazyClass(options); | ||
const isVue2 = Vue.version.split('.')[0] === '2'; | ||
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) | ||
}); | ||
} else { | ||
Vue.directive('lazy', { | ||
bind: lazy.lazyLoadHandler.bind(lazy), | ||
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() { | ||
lazy.remove(this.el); | ||
} | ||
}); | ||
} | ||
const useCheckInView = (el, preLoad) => { | ||
let rect = reactive({}); | ||
const getRect = () => { | ||
rect = el.value.getBoundingClientRect(); | ||
}; | ||
const checkInView = () => { | ||
getRect(); | ||
return inBrowser && rect.top < window.innerHeight * preLoad && rect.bottom > 0 && rect.left < window.innerWidth * preLoad && rect.right > 0; | ||
}; | ||
return { | ||
rect, | ||
checkInView | ||
}; | ||
}; | ||
const LazyComponent = lazy => { | ||
return { | ||
props: { | ||
tag: { | ||
type: String, | ||
default: 'div' | ||
} | ||
}, | ||
render(h) { | ||
return h(this.tag, null, this.show ? this.$slots.default : null); | ||
}, | ||
data() { | ||
return { | ||
el: null, | ||
state: { | ||
loaded: false | ||
var LazyComponent = (lazy => { | ||
return defineComponent({ | ||
props: { | ||
tag: { | ||
type: String, | ||
default: 'div' | ||
} | ||
}, | ||
rect: {}, | ||
show: false | ||
}; | ||
}, | ||
mounted() { | ||
this.el = this.$el; | ||
lazy.addLazyBox(this); | ||
lazy.lazyLoadHandler(); | ||
}, | ||
beforeDestroy() { | ||
lazy.removeComponent(this); | ||
}, | ||
methods: { | ||
getRect() { | ||
this.rect = this.$el.getBoundingClientRect(); | ||
}, | ||
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() { | ||
this.show = true; | ||
this.state.loaded = true; | ||
this.$emit('show', this); | ||
}, | ||
destroy() { | ||
return this.$destroy; | ||
} | ||
} | ||
}; | ||
}; | ||
emits: ['show'], | ||
setup(props, { emit, slots }) { | ||
const el = ref(); | ||
const state = reactive({ | ||
loaded: false, | ||
error: false, | ||
attempt: 0 | ||
}); | ||
const show = ref(false); | ||
const { rect, checkInView } = useCheckInView(el, lazy.options.preLoad); | ||
const load = () => { | ||
show.value = true; | ||
state.loaded = true; | ||
emit('show', show.value); | ||
}; | ||
const vm = computed(() => { | ||
return { | ||
el: el.value, | ||
rect, | ||
checkInView, | ||
load, | ||
state | ||
}; | ||
}); | ||
onMounted(() => { | ||
lazy.addLazyBox(vm.value); | ||
lazy.lazyLoadHandler(); | ||
}); | ||
onUnmounted(() => { | ||
lazy.removeComponent(vm.value); | ||
}); | ||
return () => { | ||
var _a; | ||
return createVNode(props.tag, { | ||
ref: el | ||
}, [show.value && ((_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots))]); | ||
}; | ||
} | ||
}); | ||
}); | ||
LazyComponent.install = function (Vue, options = {}) { | ||
const LazyClass = Lazy(Vue); | ||
const lazy = new LazyClass(options); | ||
Vue.component('lazy-component', LazyComponent(lazy)); | ||
}; | ||
class LazyContainerMananger { | ||
constructor({ lazy }) { | ||
this.lazy = lazy; | ||
lazy.lazyContainerMananger = this; | ||
this._queue = []; | ||
} | ||
bind(el, binding, vnode) { | ||
const container = new LazyContainer({ el, binding, vnode, lazy: this.lazy }); | ||
this._queue.push(container); | ||
} | ||
update(el, binding, vnode) { | ||
const container = find(this._queue, item => item.el === el); | ||
if (!container) return; | ||
container.update({ el, binding, vnode }); | ||
} | ||
unbind(el, binding, vnode) { | ||
const container = find(this._queue, item => item.el === el); | ||
if (!container) return; | ||
container.clear(); | ||
remove(this._queue, container); | ||
} | ||
constructor(lazy) { | ||
this.lazy = lazy; | ||
lazy.lazyContainerMananger = this; | ||
this._queue = []; | ||
} | ||
bind(el, binding, vnode) { | ||
const container = new LazyContainer(el, binding, vnode, this.lazy); | ||
this._queue.push(container); | ||
} | ||
update(el, binding, vnode) { | ||
const container = this._queue.find(item => item.el === el); | ||
if (!container) return; | ||
container.update(el, binding); | ||
} | ||
unbind(el, binding, vnode) { | ||
const container = this._queue.find(item => item.el === el); | ||
if (!container) return; | ||
container.clear(); | ||
remove(this._queue, container); | ||
} | ||
} | ||
const defaultOptions = { | ||
selector: 'img' | ||
selector: 'img', | ||
error: '', | ||
loading: '' | ||
}; | ||
class LazyContainer { | ||
constructor({ el, binding, vnode, lazy }) { | ||
this.el = null; | ||
this.vnode = vnode; | ||
this.binding = binding; | ||
this.options = {}; | ||
this.lazy = lazy; | ||
this._queue = []; | ||
this.update({ el, binding }); | ||
} | ||
update({ el, binding }) { | ||
this.el = el; | ||
this.options = assignDeep({}, defaultOptions, binding.value); | ||
const imgs = this.getImgs(); | ||
imgs.forEach(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); | ||
}); | ||
} | ||
getImgs() { | ||
return ArrayFrom(this.el.querySelectorAll(this.options.selector)); | ||
} | ||
clear() { | ||
const imgs = this.getImgs(); | ||
imgs.forEach(el => this.lazy.remove(el)); | ||
this.vnode = null; | ||
this.binding = null; | ||
this.lazy = null; | ||
} | ||
} | ||
LazyContainer.install = (Vue, options = {}) => { | ||
const LazyClass = Lazy(Vue); | ||
const lazy = new LazyClass(options); | ||
const lazyContainer = new LazyContainer({ lazy }); | ||
const isVue2 = Vue.version.split('.')[0] === '2'; | ||
if (isVue2) { | ||
Vue.directive('lazy-container', { | ||
bind: lazyContainer.bind.bind(lazyContainer), | ||
componentUpdated: lazyContainer.update.bind(lazyContainer), | ||
unbind: lazyContainer.unbind.bind(lazyContainer) | ||
}); | ||
} else { | ||
Vue.directive('lazy-container', { | ||
update(newValue, oldValue) { | ||
lazyContainer.update(this.el, { | ||
modifiers: this.modifiers || {}, | ||
arg: this.arg, | ||
value: newValue, | ||
oldValue: oldValue | ||
}, { | ||
context: this.vm | ||
constructor(el, binding, vnode, lazy) { | ||
this.el = el; | ||
this.vnode = vnode; | ||
this.binding = binding; | ||
this.options = {}; | ||
this.lazy = lazy; | ||
this._queue = []; | ||
this.update(el, binding); | ||
} | ||
update(el, binding) { | ||
this.el = el; | ||
this.options = assignDeep({}, defaultOptions, binding.value); | ||
const imgs = this.getImgs(); | ||
imgs.forEach(el => { | ||
this.lazy.add(el, assignDeep({}, this.binding, { | ||
value: { | ||
src: el.getAttribute('data-src') || el.dataset.src, | ||
error: el.getAttribute('data-error') || el.dataset.error || this.options.error, | ||
loading: el.getAttribute('data-loading') || el.dataset.loading || this.options.loading | ||
} | ||
}), this.vnode); | ||
}); | ||
}, | ||
unbind() { | ||
lazyContainer.unbind(this.el); | ||
} | ||
}); | ||
} | ||
}; | ||
const LazyImage = lazyManager => { | ||
return { | ||
props: { | ||
src: [String, Object], | ||
tag: { | ||
type: String, | ||
default: 'img' | ||
} | ||
}, | ||
render(h) { | ||
return h(this.tag, { | ||
attrs: { | ||
src: this.renderSrc | ||
} | ||
}, this.$slots.default); | ||
}, | ||
data() { | ||
return { | ||
el: null, | ||
options: { | ||
src: '', | ||
error: '', | ||
loading: '', | ||
attempt: lazyManager.options.attempt | ||
}, | ||
state: { | ||
loaded: false, | ||
error: false, | ||
attempt: 0 | ||
}, | ||
rect: {}, | ||
renderSrc: '' | ||
}; | ||
}, | ||
watch: { | ||
src() { | ||
this.init(); | ||
lazyManager.addLazyBox(this); | ||
lazyManager.lazyLoadHandler(); | ||
} | ||
}, | ||
created() { | ||
this.init(); | ||
this.renderSrc = this.options.loading; | ||
}, | ||
mounted() { | ||
this.el = this.$el; | ||
lazyManager.addLazyBox(this); | ||
lazyManager.lazyLoadHandler(); | ||
}, | ||
beforeDestroy() { | ||
lazyManager.removeComponent(this); | ||
}, | ||
methods: { | ||
init() { | ||
const { src, loading, error } = lazyManager._valueFormatter(this.src); | ||
this.state.loaded = false; | ||
this.options.src = src; | ||
this.options.error = error; | ||
this.options.loading = loading; | ||
this.renderSrc = this.options.loading; | ||
}, | ||
getRect() { | ||
this.rect = this.$el.getBoundingClientRect(); | ||
}, | ||
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(onFinish = 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; | ||
} | ||
const src = this.options.src; | ||
loadImageAsync({ src }, ({ src }) => { | ||
this.renderSrc = src; | ||
this.state.loaded = true; | ||
}, e => { | ||
this.state.attempt++; | ||
this.renderSrc = this.options.error; | ||
this.state.error = true; | ||
}); | ||
} | ||
} | ||
}; | ||
}; | ||
LazyImage.install = (Vue, options = {}) => { | ||
const LazyClass = Lazy(Vue); | ||
const lazy = new LazyClass(options); | ||
Vue.component('lazy-image', LazyImage(lazy)); | ||
}; | ||
var index = { | ||
/* | ||
* install function | ||
* @param {Vue} Vue | ||
* @param {object} options lazyload options | ||
*/ | ||
install(Vue, options = {}) { | ||
const LazyClass = Lazy(Vue); | ||
const lazy = new LazyClass(options); | ||
const lazyContainer = new LazyContainerMananger({ lazy }); | ||
const isVue2 = Vue.version.split('.')[0] === '2'; | ||
Vue.prototype.$Lazyload = lazy; | ||
if (options.lazyComponent) { | ||
Vue.component('lazy-component', LazyComponent(lazy)); | ||
getImgs() { | ||
return Array.from(this.el.querySelectorAll(this.options.selector)); | ||
} | ||
if (options.lazyImage) { | ||
Vue.component('lazy-image', LazyImage(lazy)); | ||
clear() { | ||
const imgs = this.getImgs(); | ||
imgs.forEach(el => this.lazy.remove(el)); | ||
this.vnode = null; | ||
this.binding = null; | ||
this.lazy = null; | ||
} | ||
} | ||
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(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() { | ||
lazy.remove(this.el); | ||
var LazyImage = (lazy => { | ||
return defineComponent({ | ||
setup(props, { slots }) { | ||
const el = ref(); | ||
const options = reactive({ | ||
src: '', | ||
error: '', | ||
loading: '', | ||
attempt: lazy.options.attempt | ||
}); | ||
const state = reactive({ | ||
loaded: false, | ||
error: false, | ||
attempt: 0 | ||
}); | ||
const { rect, checkInView } = useCheckInView(el, lazy.options.preLoad); | ||
const renderSrc = ref(''); | ||
const load = (onFinish = noop) => { | ||
if (state.attempt > options.attempt - 1 && state.error) { | ||
if (!lazy.options.silent) console.log(`VueLazyload log: ${options.src} tried too more than ${options.attempt} times`); | ||
return onFinish(); | ||
} | ||
const src = options.src; | ||
loadImageAsync({ src }, ({ src }) => { | ||
renderSrc.value = src; | ||
state.loaded = true; | ||
}, () => { | ||
state.attempt++; | ||
renderSrc.value = options.error; | ||
state.error = true; | ||
}); | ||
}; | ||
const vm = computed(() => { | ||
return { | ||
el: el.value, | ||
rect, | ||
checkInView, | ||
load, | ||
state | ||
}; | ||
}); | ||
onMounted(() => { | ||
lazy.addLazyBox(vm.value); | ||
lazy.lazyLoadHandler(); | ||
}); | ||
onUnmounted(() => { | ||
lazy.removeComponent(vm.value); | ||
}); | ||
const init = () => { | ||
const { src, loading, error } = lazy._valueFormatter(props.src); | ||
state.loaded = false; | ||
options.src = src; | ||
options.error = error; | ||
options.loading = loading; | ||
renderSrc.value = options.loading; | ||
}; | ||
watch(() => props.src, () => { | ||
init(); | ||
lazy.addLazyBox(vm.value); | ||
lazy.lazyLoadHandler(); | ||
}, { | ||
immediate: true | ||
}); | ||
return () => { | ||
var _a; | ||
return createVNode(props.tag || 'img', { | ||
src: renderSrc.value, | ||
ref: el | ||
}, [(_a = slots.default) === null || _a === void 0 ? void 0 : _a.call(slots)]); | ||
}; | ||
} | ||
}); | ||
}); | ||
}); | ||
Vue.directive('lazy-container', { | ||
update(newValue, oldValue) { | ||
lazyContainer.update(this.el, { | ||
modifiers: this.modifiers || {}, | ||
arg: this.arg, | ||
value: newValue, | ||
oldValue: oldValue | ||
}, { | ||
context: this.vm | ||
}); | ||
}, | ||
unbind() { | ||
lazyContainer.unbind(this.el); | ||
var index = { | ||
/* | ||
* install function | ||
* @param {Vue} Vue | ||
* @param {object} options lazyload options | ||
*/ | ||
install(Vue, options = {}) { | ||
const lazy = new Lazy(options); | ||
const lazyContainer = new LazyContainerMananger(lazy); | ||
const vueVersion = Number(Vue.version.split('.')[0]); | ||
if (vueVersion < 3) return new Error('Vue version at least 3.0'); | ||
Vue.config.globalProperties.$Lazyload = lazy; | ||
Vue.provide('Lazyload', lazy); | ||
if (options.lazyComponent) { | ||
Vue.component('lazy-component', LazyComponent(lazy)); | ||
} | ||
}); | ||
if (options.lazyImage) { | ||
Vue.component('lazy-image', LazyImage(lazy)); | ||
} | ||
Vue.directive('lazy', { | ||
beforeMount: lazy.add.bind(lazy), | ||
beforeUpdate: lazy.update.bind(lazy), | ||
updated: lazy.lazyLoadHandler.bind(lazy), | ||
unmounted: lazy.remove.bind(lazy) | ||
}); | ||
Vue.directive('lazy-container', { | ||
beforeMount: lazyContainer.bind.bind(lazyContainer), | ||
updated: lazyContainer.update.bind(lazyContainer), | ||
unmounted: lazyContainer.unbind.bind(lazyContainer) | ||
}); | ||
} | ||
} | ||
}; | ||
export default index; | ||
export { Lazy, LazyComponent, LazyContainerMananger as LazyContainer, LazyImage }; | ||
export { index as default }; |
/*! | ||
* Vue-Lazyload.js v1.3.4 | ||
* (c) 2021 Awe <hilongjw@gmail.com> | ||
* Vue-Lazyload.js v3.0.0-alpha.0 | ||
* (c) 2022 Awe <hilongjw@gmail.com> | ||
* Released under the MIT License. | ||
*/ | ||
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).VueLazyload={})}(this,(function(t){"use strict"; | ||
/*! | ||
* is-primitive <https://github.com/jonschlinkert/is-primitive> | ||
* | ||
* Copyright (c) 2014-2015, Jon Schlinkert. | ||
* Licensed under the MIT License. | ||
*/var e=function(t){return null==t||"function"!=typeof t&&"object"!=typeof t},r=Object.freeze({__proto__:null,default:e,__moduleExports:e}),i=function(t,e){if(null==t)throw new TypeError("expected first argument to be an object.");if(void 0===e||"undefined"==typeof Symbol)return t;if("function"!=typeof Object.getOwnPropertySymbols)return t;for(var r=Object.prototype.propertyIsEnumerable,i=Object(t),n=arguments.length,s=0;++s<n;)for(var o=Object(arguments[s]),a=Object.getOwnPropertySymbols(o),d=0;d<a.length;d++){var l=a[d];r.call(o,l)&&(i[l]=o[l])}return i},n=Object.freeze({__proto__:null,default:i,__moduleExports:i}),s=Object.prototype.toString,o=function(t){var e=typeof t;return"undefined"===e?"undefined":null===t?"null":!0===t||!1===t||t instanceof Boolean?"boolean":"string"===e||t instanceof String?"string":"number"===e||t instanceof Number?"number":"function"===e||t instanceof Function?void 0!==t.constructor.name&&"Generator"===t.constructor.name.slice(0,9)?"generatorfunction":"function":void 0!==Array.isArray&&Array.isArray(t)?"array":t instanceof RegExp?"regexp":t instanceof Date?"date":"[object RegExp]"===(e=s.call(t))?"regexp":"[object Date]"===e?"date":"[object Arguments]"===e?"arguments":"[object Error]"===e?"error":"[object Promise]"===e?"promise":function(t){return t.constructor&&"function"==typeof t.constructor.isBuffer&&t.constructor.isBuffer(t)}(t)?"buffer":"[object Set]"===e?"set":"[object WeakSet]"===e?"weakset":"[object Map]"===e?"map":"[object WeakMap]"===e?"weakmap":"[object Symbol]"===e?"symbol":"[object Map Iterator]"===e?"mapiterator":"[object Set Iterator]"===e?"setiterator":"[object String Iterator]"===e?"stringiterator":"[object Array Iterator]"===e?"arrayiterator":"[object Int8Array]"===e?"int8array":"[object Uint8Array]"===e?"uint8array":"[object Uint8ClampedArray]"===e?"uint8clampedarray":"[object Int16Array]"===e?"int16array":"[object Uint16Array]"===e?"uint16array":"[object Int32Array]"===e?"int32array":"[object Uint32Array]"===e?"uint32array":"[object Float32Array]"===e?"float32array":"[object Float64Array]"===e?"float64array":"object"};var a=Object.freeze({__proto__:null,default:o,__moduleExports:o}),d=r&&e||r,l=n&&i||n,h=a&&o||a;function c(t){t=t||{};var e=arguments.length,r=0;if(1===e)return t;for(;++r<e;){var i=arguments[r];d(t)&&(t=i),p(i)&&u(t,i)}return t}function u(t,e){for(var r in l(t,e),e)if(b(r)&&f(e,r)){var i=e[r];p(i)?("undefined"===h(t[r])&&"function"===h(i)&&(t[r]=i),t[r]=c(t[r]||{},i)):t[r]=i}return t}function p(t){return"object"===h(t)||"function"===h(t)}function f(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function b(t){return"__proto__"!==t&&"constructor"!==t&&"prototype"!==t}var g=c;const m="undefined"!=typeof window&&null!==window,v=function(){if(m&&"IntersectionObserver"in window&&"IntersectionObserverEntry"in window&&"intersectionRatio"in window.IntersectionObserverEntry.prototype)return"isIntersecting"in window.IntersectionObserverEntry.prototype||Object.defineProperty(window.IntersectionObserverEntry.prototype,"isIntersecting",{get:function(){return this.intersectionRatio>0}}),!0;return!1}();const y="event",w="observer",_=function(){if(m)return"function"==typeof window.CustomEvent?window.CustomEvent:(t.prototype=window.Event.prototype,t);function t(t,e){e=e||{bubbles:!1,cancelable:!1,detail:void 0};var r=document.createEvent("CustomEvent");return r.initCustomEvent(t,e.bubbles,e.cancelable,e.detail),r}}();function L(t,e){if(!t.length)return;const r=t.indexOf(e);return r>-1?t.splice(r,1):void 0}function E(t,e){if("IMG"!==t.tagName||!t.getAttribute("data-srcset"))return;let r=t.getAttribute("data-srcset");const i=[],n=t.parentNode.offsetWidth*e;let s,o,a;r=r.trim().split(","),r.map((t=>{t=t.trim(),s=t.lastIndexOf(" "),-1===s?(o=t,a=999998):(o=t.substr(0,s),a=parseInt(t.substr(s+1,t.length-s-2),10)),i.push([a,o])})),i.sort((function(t,e){if(t[0]<e[0])return 1;if(t[0]>e[0])return-1;if(t[0]===e[0]){if(-1!==e[1].indexOf(".webp",e[1].length-5))return 1;if(-1!==t[1].indexOf(".webp",t[1].length-5))return-1}return 0}));let d,l="";for(let t=0;t<i.length;t++){d=i[t],l=d[1];const e=i[t+1];if(e&&e[0]<n){l=d[1];break}if(!e){l=d[1];break}}return l}function z(t,e){let r;for(let i=0,n=t.length;i<n;i++)if(e(t[i])){r=t[i];break}return r}const A=(t=1)=>m&&window.devicePixelRatio||t;function j(){if(!m)return!1;let t=!0;try{const e=document.createElement("canvas");e.getContext&&e.getContext("2d")&&(t=0===e.toDataURL("image/webp").indexOf("data:image/webp"))}catch(e){t=!1}return t}const x=function(){if(!m)return;let t=!1;try{let e=Object.defineProperty({},"passive",{get:function(){t=!0}});window.addEventListener("test",null,e)}catch(t){}return t}(),O={on(t,e,r,i=!1){x?t.addEventListener(e,r,{capture:i,passive:!0}):t.addEventListener(e,r,i)},off(t,e,r,i=!1){t.removeEventListener(e,r,i)}},$=(t,e,r)=>{let i=new Image;if(!t||!t.src){const t=new Error("image src is required");return r(t)}i.src=t.src,t.cors&&(i.crossOrigin=t.cors),i.onload=function(){e({naturalHeight:i.naturalHeight,naturalWidth:i.naturalWidth,src:i.src})},i.onerror=function(t){r(t)}},T=(t,e)=>"undefined"!=typeof getComputedStyle?getComputedStyle(t,null).getPropertyValue(e):t.style[e],I=t=>T(t,"overflow")+T(t,"overflow-y")+T(t,"overflow-x");function C(){}class H{constructor({max:t}){this.options={max:t||100},this._caches=[]}has(t){return this._caches.indexOf(t)>-1}add(t){this.has(t)||(this._caches.push(t),this._caches.length>this.options.max&&this.free())}free(){this._caches.shift()}}class S{constructor({el:t,src:e,error:r,loading:i,bindType:n,$parent:s,options:o,cors:a,elRenderer:d,imageCache:l}){this.el=t,this.src=e,this.error=r,this.loading=i,this.bindType=n,this.attempt=0,this.cors=a,this.naturalHeight=0,this.naturalWidth=0,this.options=o,this.rect=null,this.$parent=s,this.elRenderer=d,this._imageCache=l,this.performanceData={init:Date.now(),loadStart:0,loadEnd:0},this.filter(),this.initState(),this.render("loading",!1)}initState(){"dataset"in this.el?this.el.dataset.src=this.src:this.el.setAttribute("data-src",this.src),this.state={loading:!1,error:!1,loaded:!1,rendered:!1}}record(t){this.performanceData[t]=Date.now()}update({src:t,loading:e,error:r}){const i=this.src;this.src=t,this.loading=e,this.error=r,this.filter(),i!==this.src&&(this.attempt=0,this.initState())}getRect(){this.rect=this.el.getBoundingClientRect()}checkInView(){return this.getRect(),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}filter(){(function(t){if(!(t instanceof Object))return[];if(Object.keys)return Object.keys(t);{let e=[];for(let r in t)t.hasOwnProperty(r)&&e.push(r);return e}})(this.options.filter).map((t=>{this.options.filter[t](this,this.options)}))}renderLoading(t){this.state.loading=!0,$({src:this.loading,cors:this.cors},(e=>{this.render("loading",!1),this.state.loading=!1,t()}),(()=>{t(),this.state.loading=!1,this.options.silent||console.warn(`VueLazyload log: load failed with loading image(${this.loading})`)}))}load(t=C){return this.attempt>this.options.attempt-1&&this.state.error?(this.options.silent||console.log(`VueLazyload log: ${this.src} tried too more than ${this.options.attempt} times`),void t()):this.state.rendered&&this.state.loaded?void 0:this._imageCache.has(this.src)?(this.state.loaded=!0,this.render("loaded",!0),this.state.rendered=!0,t()):void this.renderLoading((()=>{this.attempt++,this.options.adapter.beforeLoad&&this.options.adapter.beforeLoad(this,this.options),this.record("loadStart"),$({src:this.src,cors:this.cors},(e=>{this.naturalHeight=e.naturalHeight,this.naturalWidth=e.naturalWidth,this.state.loaded=!0,this.state.error=!1,this.record("loadEnd"),this.render("loaded",!1),this.state.rendered=!0,this._imageCache.add(this.src),t()}),(t=>{!this.options.silent&&console.error(t),this.state.error=!0,this.state.loaded=!1,this.render("error",!1)}))}))}render(t,e){this.elRenderer(this,t,e)}performance(){let t="loading",e=0;return this.state.loaded&&(t="loaded",e=(this.performanceData.loadEnd-this.performanceData.loadStart)/1e3),this.state.error&&(t="error"),{src:this.src,state:t,time:e}}$destroy(){this.el=null,this.src=null,this.error=null,this.loading=null,this.bindType=null,this.attempt=0}}const Q="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",R=["scroll","wheel","mousewheel","resize","animationend","transitionend","touchmove"],k={rootMargin:"0px",threshold:0};function B(t){return class{constructor({preLoad:t,error:e,throttleWait:r,preLoadTop:i,dispatchEvent:n,loading:s,attempt:o,silent:a=!0,scale:d,listenEvents:l,hasbind:h,filter:c,adapter:u,observer:p,observerOptions:f}){this.version='"1.3.4"',this.mode=y,this.ListenerQueue=[],this.TargetIndex=0,this.TargetQueue=[],this.options={silent:a,dispatchEvent:!!n,throttleWait:r||200,preLoad:t||1.3,preLoadTop:i||0,error:e||Q,loading:s||Q,attempt:o||3,scale:d||A(d),ListenEvents:l||R,hasbind:!1,supportWebp:j(),filter:c||{},adapter:u||{},observer:!!p,observerOptions:f||k},this._initEvent(),this._imageCache=new H({max:200}),this.lazyLoadHandler=function(t,e){let r=null,i=null,n=0,s=!1;return function(){if(s=!0,r)return;let o=Date.now()-n,a=this,d=arguments,l=function(){n=Date.now(),r=!1,t.apply(a,d)};o>=e?l():r=setTimeout(l,e),s&&(clearTimeout(i),i=setTimeout(l,2*e))}}(this._lazyLoadHandler.bind(this),this.options.throttleWait),this.setMode(this.options.observer?w:y)}config(t={}){g(this.options,t)}performance(){let t=[];return this.ListenerQueue.map((e=>{t.push(e.performance())})),t}addLazyBox(t){this.ListenerQueue.push(t),m&&(this._addListenerTarget(window),this._observer&&this._observer.observe(t.el),t.$el&&t.$el.parentNode&&this._addListenerTarget(t.$el.parentNode))}add(e,r,i){if(function(t,e){let r=!1;for(let i=0,n=t.length;i<n;i++)if(e(t[i])){r=!0;break}return r}(this.ListenerQueue,(t=>t.el===e)))return this.update(e,r),t.nextTick(this.lazyLoadHandler);let{src:n,loading:s,error:o,cors:a}=this._valueFormatter(r.value);t.nextTick((()=>{n=E(e,this.options.scale)||n,this._observer&&this._observer.observe(e);const d=Object.keys(r.modifiers)[0];let l;d&&(l=i.context.$refs[d],l=l?l.$el||l:document.getElementById(d)),l||(l=(t=>{if(!m)return;if(!(t instanceof HTMLElement))return window;let e=t;for(;e&&e!==document.body&&e!==document.documentElement&&e.parentNode;){if(/(scroll|auto)/.test(I(e)))return e;e=e.parentNode}return window})(e));const h=new S({bindType:r.arg,$parent:l,el:e,loading:s,error:o,src:n,cors:a,elRenderer:this._elRenderer.bind(this),options:this.options,imageCache:this._imageCache});this.ListenerQueue.push(h),m&&(this._addListenerTarget(window),this._addListenerTarget(l)),this.lazyLoadHandler(),t.nextTick((()=>this.lazyLoadHandler()))}))}update(e,r,i){let{src:n,loading:s,error:o}=this._valueFormatter(r.value);n=E(e,this.options.scale)||n;const a=z(this.ListenerQueue,(t=>t.el===e));a?a.update({src:n,loading:s,error:o}):this.add(e,r,i),this._observer&&(this._observer.unobserve(e),this._observer.observe(e)),this.lazyLoadHandler(),t.nextTick((()=>this.lazyLoadHandler()))}remove(t){if(!t)return;this._observer&&this._observer.unobserve(t);const e=z(this.ListenerQueue,(e=>e.el===t));e&&(this._removeListenerTarget(e.$parent),this._removeListenerTarget(window),L(this.ListenerQueue,e),e.$destroy())}removeComponent(t){t&&(L(this.ListenerQueue,t),this._observer&&this._observer.unobserve(t.el),t.$parent&&t.$el.parentNode&&this._removeListenerTarget(t.$el.parentNode),this._removeListenerTarget(window))}setMode(t){v||t!==w||(t=y),this.mode=t,t===y?(this._observer&&(this.ListenerQueue.forEach((t=>{this._observer.unobserve(t.el)})),this._observer=null),this.TargetQueue.forEach((t=>{this._initListen(t.el,!0)}))):(this.TargetQueue.forEach((t=>{this._initListen(t.el,!1)})),this._initIntersectionObserver())}_addListenerTarget(t){if(!t)return;let e=z(this.TargetQueue,(e=>e.el===t));return e?e.childrenCount++:(e={el:t,id:++this.TargetIndex,childrenCount:1,listened:!0},this.mode===y&&this._initListen(e.el,!0),this.TargetQueue.push(e)),this.TargetIndex}_removeListenerTarget(t){this.TargetQueue.forEach(((e,r)=>{e.el===t&&(e.childrenCount--,e.childrenCount||(this._initListen(e.el,!1),this.TargetQueue.splice(r,1),e=null))}))}_initListen(t,e){this.options.ListenEvents.forEach((r=>O[e?"on":"off"](t,r,this.lazyLoadHandler)))}_initEvent(){this.Event={listeners:{loading:[],loaded:[],error:[]}},this.$on=(t,e)=>{this.Event.listeners[t]||(this.Event.listeners[t]=[]),this.Event.listeners[t].push(e)},this.$once=(t,e)=>{const r=this;this.$on(t,(function i(){r.$off(t,i),e.apply(r,arguments)}))},this.$off=(t,e)=>{if(e)L(this.Event.listeners[t],e);else{if(!this.Event.listeners[t])return;this.Event.listeners[t].length=0}},this.$emit=(t,e,r)=>{this.Event.listeners[t]&&this.Event.listeners[t].forEach((t=>t(e,r)))}}_lazyLoadHandler(){const t=[];this.ListenerQueue.forEach(((e,r)=>{e.el&&e.el.parentNode||t.push(e);e.checkInView()&&e.load()})),t.forEach((t=>{L(this.ListenerQueue,t),t.$destroy()}))}_initIntersectionObserver(){v&&(this._observer=new IntersectionObserver(this._observerHandler.bind(this),this.options.observerOptions),this.ListenerQueue.length&&this.ListenerQueue.forEach((t=>{this._observer.observe(t.el)})))}_observerHandler(t,e){t.forEach((t=>{t.isIntersecting&&this.ListenerQueue.forEach((e=>{if(e.el===t.target){if(e.state.loaded)return this._observer.unobserve(e.el);e.load()}}))}))}_elRenderer(t,e,r){if(!t.el)return;const{el:i,bindType:n}=t;let s;switch(e){case"loading":s=t.loading;break;case"error":s=t.error;break;default:s=t.src}if(n?i.style[n]='url("'+s+'")':i.getAttribute("src")!==s&&i.setAttribute("src",s),i.setAttribute("lazy",e),this.$emit(e,t,r),this.options.adapter[e]&&this.options.adapter[e](t,this.options),this.options.dispatchEvent){const r=new _(e,{detail:t});i.dispatchEvent(r)}}_valueFormatter(t){let e=t,r=this.options.loading,i=this.options.error;var n;return null!==(n=t)&&"object"==typeof n&&(t.src||this.options.silent||console.error("Vue Lazyload warning: miss src with "+t),e=t.src,r=t.loading||this.options.loading,i=t.error||this.options.error),{src:e,loading:r,error:i}}}}B.install=(t,e={})=>{const r=new(B(t))(e);"2"===t.version.split(".")[0]?t.directive("lazy",{bind:r.add.bind(r),update:r.update.bind(r),componentUpdated:r.lazyLoadHandler.bind(r),unbind:r.remove.bind(r)}):t.directive("lazy",{bind:r.lazyLoadHandler.bind(r),update(t,e){g(this.vm.$refs,this.vm.$els),r.add(this.el,{modifiers:this.modifiers||{},arg:this.arg,value:t,oldValue:e},{context:this.vm})},unbind(){r.remove(this.el)}})};const W=t=>({props:{tag:{type:String,default:"div"}},render(t){return t(this.tag,null,this.show?this.$slots.default:null)},data:()=>({el:null,state:{loaded:!1},rect:{},show:!1}),mounted(){this.el=this.$el,t.addLazyBox(this),t.lazyLoadHandler()},beforeDestroy(){t.removeComponent(this)},methods:{getRect(){this.rect=this.$el.getBoundingClientRect()},checkInView(){return this.getRect(),m&&this.rect.top<window.innerHeight*t.options.preLoad&&this.rect.bottom>0&&this.rect.left<window.innerWidth*t.options.preLoad&&this.rect.right>0},load(){this.show=!0,this.state.loaded=!0,this.$emit("show",this)},destroy(){return this.$destroy}}});W.install=function(t,e={}){const r=new(B(t))(e);t.component("lazy-component",W(r))};class D{constructor({lazy:t}){this.lazy=t,t.lazyContainerMananger=this,this._queue=[]}bind(t,e,r){const i=new P({el:t,binding:e,vnode:r,lazy:this.lazy});this._queue.push(i)}update(t,e,r){const i=z(this._queue,(e=>e.el===t));i&&i.update({el:t,binding:e,vnode:r})}unbind(t,e,r){const i=z(this._queue,(e=>e.el===t));i&&(i.clear(),L(this._queue,i))}}const V={selector:"img"};class P{constructor({el:t,binding:e,vnode:r,lazy:i}){this.el=null,this.vnode=r,this.binding=e,this.options={},this.lazy=i,this._queue=[],this.update({el:t,binding:e})}update({el:t,binding:e}){this.el=t,this.options=g({},V,e.value);this.getImgs().forEach((t=>{this.lazy.add(t,g({},this.binding,{value:{src:"dataset"in t?t.dataset.src:t.getAttribute("data-src"),error:("dataset"in t?t.dataset.error:t.getAttribute("data-error"))||this.options.error,loading:("dataset"in t?t.dataset.loading:t.getAttribute("data-loading"))||this.options.loading}}),this.vnode)}))}getImgs(){return function(t){let e=t.length;const r=[];for(let i=0;i<e;i++)r.push(t[i]);return r}(this.el.querySelectorAll(this.options.selector))}clear(){this.getImgs().forEach((t=>this.lazy.remove(t))),this.vnode=null,this.binding=null,this.lazy=null}}P.install=(t,e={})=>{const r=new(B(t))(e),i=new P({lazy:r});"2"===t.version.split(".")[0]?t.directive("lazy-container",{bind:i.bind.bind(i),componentUpdated:i.update.bind(i),unbind:i.unbind.bind(i)}):t.directive("lazy-container",{update(t,e){i.update(this.el,{modifiers:this.modifiers||{},arg:this.arg,value:t,oldValue:e},{context:this.vm})},unbind(){i.unbind(this.el)}})};const M=t=>({props:{src:[String,Object],tag:{type:String,default:"img"}},render(t){return t(this.tag,{attrs:{src:this.renderSrc}},this.$slots.default)},data:()=>({el:null,options:{src:"",error:"",loading:"",attempt:t.options.attempt},state:{loaded:!1,error:!1,attempt:0},rect:{},renderSrc:""}),watch:{src(){this.init(),t.addLazyBox(this),t.lazyLoadHandler()}},created(){this.init(),this.renderSrc=this.options.loading},mounted(){this.el=this.$el,t.addLazyBox(this),t.lazyLoadHandler()},beforeDestroy(){t.removeComponent(this)},methods:{init(){const{src:e,loading:r,error:i}=t._valueFormatter(this.src);this.state.loaded=!1,this.options.src=e,this.options.error=i,this.options.loading=r,this.renderSrc=this.options.loading},getRect(){this.rect=this.$el.getBoundingClientRect()},checkInView(){return this.getRect(),m&&this.rect.top<window.innerHeight*t.options.preLoad&&this.rect.bottom>0&&this.rect.left<window.innerWidth*t.options.preLoad&&this.rect.right>0},load(e=C){if(this.state.attempt>this.options.attempt-1&&this.state.error)return t.options.silent||console.log(`VueLazyload log: ${this.options.src} tried too more than ${this.options.attempt} times`),void e();const r=this.options.src;$({src:r},(({src:t})=>{this.renderSrc=t,this.state.loaded=!0}),(t=>{this.state.attempt++,this.renderSrc=this.options.error,this.state.error=!0}))}}});M.install=(t,e={})=>{const r=new(B(t))(e);t.component("lazy-image",M(r))};var N={install(t,e={}){const r=new(B(t))(e),i=new D({lazy:r}),n="2"===t.version.split(".")[0];t.prototype.$Lazyload=r,e.lazyComponent&&t.component("lazy-component",W(r)),e.lazyImage&&t.component("lazy-image",M(r)),n?(t.directive("lazy",{bind:r.add.bind(r),update:r.update.bind(r),componentUpdated:r.lazyLoadHandler.bind(r),unbind:r.remove.bind(r)}),t.directive("lazy-container",{bind:i.bind.bind(i),componentUpdated:i.update.bind(i),unbind:i.unbind.bind(i)})):(t.directive("lazy",{bind:r.lazyLoadHandler.bind(r),update(t,e){g(this.vm.$refs,this.vm.$els),r.add(this.el,{modifiers:this.modifiers||{},arg:this.arg,value:t,oldValue:e},{context:this.vm})},unbind(){r.remove(this.el)}}),t.directive("lazy-container",{update(t,e){i.update(this.el,{modifiers:this.modifiers||{},arg:this.arg,value:t,oldValue:e},{context:this.vm})},unbind(){i.unbind(this.el)}}))}};t.Lazy=B,t.LazyComponent=W,t.LazyContainer=D,t.LazyImage=M,t.default=N,Object.defineProperty(t,"__esModule",{value:!0})})); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("vue")):"function"==typeof define&&define.amd?define(["exports","vue"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).VueLazyload={},e.vue)}(this,(function(e,t){"use strict";function r(e,t){return e(t={exports:{}},t.exports),t.exports}var i=r((function(e){const t=Object.prototype.toString,r=Object.prototype.propertyIsEnumerable,i=Object.getOwnPropertySymbols;e.exports=(e,...s)=>{if("function"!=typeof(o=e)&&"[object Object]"!==t.call(o)&&!Array.isArray(o))throw new TypeError("expected the first argument to be an object");var o;if(0===s.length||"function"!=typeof Symbol||"function"!=typeof i)return e;for(let t of s){let s=i(t);for(let i of s)r.call(t,i)&&(e[i]=t[i])}return e}})),s=Object.freeze({__proto__:null,default:i,__moduleExports:i}),o=s&&i||s,n=r((function(e){const t=Object.prototype.toString,r=e=>"__proto__"!==e&&"constructor"!==e&&"prototype"!==e,i=e.exports=(e,...t)=>{let n=0;var a;for(("object"==typeof(a=e)?null===a:"function"!=typeof a)&&(e=t[n++]),e||(e={});n<t.length;n++)if(s(t[n])){for(const o of Object.keys(t[n]))r(o)&&(s(e[o])&&s(t[n][o])?i(e[o],t[n][o]):e[o]=t[n][o]);o(e,t[n])}return e};function s(e){return"function"==typeof e||"[object Object]"===t.call(e)}}));const a="undefined"!=typeof window&&null!==window,l=function(){if(a&&"IntersectionObserver"in window&&"IntersectionObserverEntry"in window&&"intersectionRatio"in window.IntersectionObserverEntry.prototype)return"isIntersecting"in window.IntersectionObserverEntry.prototype||Object.defineProperty(window.IntersectionObserverEntry.prototype,"isIntersecting",{get:function(){return this.intersectionRatio>0}}),!0;return!1}();const d="event",h="observer";function c(e,t){if(!e.length)return;const r=e.indexOf(t);return r>-1?e.splice(r,1):void 0}function u(e,t){if("IMG"!==e.tagName||!e.getAttribute("data-srcset"))return"";let r=e.getAttribute("data-srcset").trim().split(",");const i=[],s=e.parentNode.offsetWidth*t;let o,n,a;r.forEach((e=>{e=e.trim(),o=e.lastIndexOf(" "),-1===o?(n=e,a=99999):(n=e.substr(0,o),a=parseInt(e.substr(o+1,e.length-o-2),10)),i.push([a,n])})),i.sort(((e,t)=>{if(e[0]<t[0])return 1;if(e[0]>t[0])return-1;if(e[0]===t[0]){if(-1!==t[1].indexOf(".webp",t[1].length-5))return 1;if(-1!==e[1].indexOf(".webp",e[1].length-5))return-1}return 0}));let l,d="";for(let e=0;e<i.length;e++){l=i[e],d=l[1];const t=i[e+1];if(t&&t[0]<s){d=l[1];break}if(!t){d=l[1];break}}return d}const p=(e=1)=>a&&window.devicePixelRatio||e;function A(){if(!a)return!1;let e=!0;function t(e,t){const r=new Image;r.onload=function(){const e=r.width>0&&r.height>0;t(e)},r.onerror=function(){t(!1)},r.src="data:image/webp;base64,"+{lossy:"UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA",lossless:"UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==",alpha:"UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==",animation:"UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA"}[e]}return t("lossy",(t=>{e=t})),t("lossless",(t=>{e=t})),t("alpha",(t=>{e=t})),t("animation",(t=>{e=t})),e}const f=function(){if(!a)return!1;let e=!1;try{const t=Object.defineProperty({},"passive",{get:function(){e=!0}});window.addEventListener("test",y,t)}catch(e){}return e}(),g={on(e,t,r,i=!1){f?e.addEventListener(t,r,{capture:i,passive:!0}):e.addEventListener(t,r,i)},off(e,t,r,i=!1){e.removeEventListener(t,r,i)}},v=(e,t,r)=>{let i=new Image;if(!e||!e.src){const e=new Error("image src is required");return r(e)}e.cors&&(i.crossOrigin=e.cors),i.src=e.src,i.onload=function(){t({naturalHeight:i.naturalHeight,naturalWidth:i.naturalWidth,src:i.src}),i=null},i.onerror=function(e){r(e)}},m=(e,t)=>"undefined"!=typeof getComputedStyle?getComputedStyle(e,null).getPropertyValue(t):e.style[t],b=e=>m(e,"overflow")+m(e,"overflowY")+m(e,"overflowX");function y(){}class w{constructor(e){this.max=e||100,this._caches=[]}has(e){return this._caches.indexOf(e)>-1}add(e){this.has(e)||(this._caches.push(e),this._caches.length>this.max&&this.free())}free(){this._caches.shift()}}class _{constructor(e,t,r,i,s,o,n,a,l,d){this.el=e,this.src=t,this.error=r,this.loading=i,this.bindType=s,this.attempt=0,this.cors=a,this.naturalHeight=0,this.naturalWidth=0,this.options=n,this.rect={},this.$parent=o,this.elRenderer=l,this._imageCache=d,this.performanceData={init:Date.now(),loadStart:0,loadEnd:0},this.filter(),this.initState(),this.render("loading",!1)}initState(){"dataset"in this.el?this.el.dataset.src=this.src:this.el.setAttribute("data-src",this.src),this.state={loading:!1,error:!1,loaded:!1,rendered:!1}}record(e){this.performanceData[e]=Date.now()}update(e){const t=this.src;this.src=e.src,this.loading=e.loading,this.error=e.error,this.filter(),t!==this.src&&(this.attempt=0,this.initState())}getRect(){this.rect=this.el.getBoundingClientRect()}checkInView(){return this.getRect(),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}filter(){for(const e in this.options.filter)this.options.filter[e](this,this.options)}renderLoading(e){this.state.loading=!0,v({src:this.loading,cors:this.cors},(()=>{this.render("loading",!1),this.state.loading=!1,e()}),(()=>{e(),this.state.loading=!1,this.options.silent||console.warn(`VueLazyload log: load failed with loading image(${this.loading})`)}))}load(e=y){return this.attempt>this.options.attempt-1&&this.state.error?(this.options.silent||console.log(`VueLazyload log: ${this.src} tried too more than ${this.options.attempt} times`),void e()):this.state.rendered&&this.state.loaded?void 0:this._imageCache.has(this.src)?(this.state.loaded=!0,this.render("loaded",!0),this.state.rendered=!0,e()):void this.renderLoading((()=>{this.attempt++,this.options.adapter.beforeLoad&&this.options.adapter.beforeLoad(this,this.options),this.record("loadStart"),v({src:this.src,cors:this.cors},(t=>{this.naturalHeight=t.naturalHeight,this.naturalWidth=t.naturalWidth,this.state.loaded=!0,this.state.error=!1,this.record("loadEnd"),this.render("loaded",!1),this.state.rendered=!0,this._imageCache.add(this.src),e()}),(e=>{!this.options.silent&&console.error(e),this.state.error=!0,this.state.loaded=!1,this.render("error",!1)}))}))}render(e,t){this.elRenderer(this,e,t)}performance(){let e="loading",t=0;return this.state.loaded&&(e="loaded",t=(this.performanceData.loadEnd-this.performanceData.loadStart)/1e3),this.state.error&&(e="error"),{src:this.src,state:e,time:t}}$destroy(){this.el=null,this.src="",this.error=null,this.loading="",this.bindType=null,this.attempt=0}}const L="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7",E=["scroll","wheel","mousewheel","resize","animationend","transitionend","touchmove"],Q={rootMargin:"0px",threshold:0};class z{constructor({preLoad:e,error:t,throttleWait:r,preLoadTop:i,dispatchEvent:s,loading:o,attempt:n,silent:a=!0,scale:l,listenEvents:c,filter:u,adapter:f,observer:g,observerOptions:v}){this.version='"3.0.0-alpha.0"',this.lazyContainerMananger=null,this.mode=d,this.ListenerQueue=[],this.TargetIndex=0,this.TargetQueue=[],this.options={silent:a,dispatchEvent:!!s,throttleWait:r||200,preLoad:e||1.3,preLoadTop:i||0,error:t||L,loading:o||L,attempt:n||3,scale:l||p(l),listenEvents:c||E,supportWebp:A(),filter:u||{},adapter:f||{},observer:!!g,observerOptions:v||Q},this._initEvent(),this._imageCache=new w(200),this.lazyLoadHandler=function(e,t){let r=null,i=0;return function(){if(r)return;const s=Date.now()-i,o=this,n=arguments,a=function(){i=Date.now(),r=!1,e.apply(o,n)};s>=t?a():r=setTimeout(a,t)}}(this._lazyLoadHandler.bind(this),this.options.throttleWait),this.setMode(this.options.observer?h:d)}performance(){const e=[];return this.ListenerQueue.map((t=>e.push(t.performance()))),e}addLazyBox(e){this.ListenerQueue.push(e),a&&(this._addListenerTarget(window),this._observer&&this._observer.observe(e.el),e.$el&&e.$el.parentNode&&this._addListenerTarget(e.$el.parentNode))}add(e,r,i){if(this.ListenerQueue.some((t=>t.el===e)))return this.update(e,r),t.nextTick(this.lazyLoadHandler);let{src:s,loading:o,error:n,cors:l}=this._valueFormatter(r.value);t.nextTick((()=>{s=u(e,this.options.scale)||s,this._observer&&this._observer.observe(e);const i=Object.keys(r.modifiers)[0];let d;i&&(d=r.instance.$refs[i],d=d?d.el||d:document.getElementById(i)),d||(d=(e=>{if(!a)return;if(!(e instanceof Element))return window;let t=e;for(;t&&t!==document.body&&t!==document.documentElement&&t.parentNode;){if(/(scroll|auto)/.test(b(t)))return t;t=t.parentNode}return window})(e));const h=new _(e,s,n,o,r.arg,d,this.options,l,this._elRenderer.bind(this),this._imageCache);this.ListenerQueue.push(h),a&&(this._addListenerTarget(window),this._addListenerTarget(d)),t.nextTick(this.lazyLoadHandler)}))}update(e,r,i){let{src:s,loading:o,error:n}=this._valueFormatter(r.value);s=u(e,this.options.scale)||s;const a=this.ListenerQueue.find((t=>t.el===e));a?a.update({src:s,loading:o,error:n}):this.add(e,r,i),this._observer&&(this._observer.unobserve(e),this._observer.observe(e)),t.nextTick(this.lazyLoadHandler)}remove(e){if(!e)return;this._observer&&this._observer.unobserve(e);const t=this.ListenerQueue.find((t=>t.el===e));t&&(this._removeListenerTarget(t.$parent),this._removeListenerTarget(window),c(this.ListenerQueue,t),t.$destroy&&t.$destroy())}removeComponent(e){e&&(c(this.ListenerQueue,e),this._observer&&this._observer.unobserve(e.el),e.$parent&&e.$el.parentNode&&this._removeListenerTarget(e.$el.parentNode),this._removeListenerTarget(window))}setMode(e){l||e!==h||(e=d),this.mode=e,e===d?(this._observer&&(this.ListenerQueue.forEach((e=>{this._observer.unobserve(e.el)})),this._observer=null),this.TargetQueue.forEach((e=>{this._initListen(e.el,!0)}))):(this.TargetQueue.forEach((e=>{this._initListen(e.el,!1)})),this._initIntersectionObserver())}_addListenerTarget(e){if(!e)return;let t=this.TargetQueue.find((t=>t.el===e));return t?t.childrenCount++:(t={el:e,id:++this.TargetIndex,childrenCount:1,listened:!0},this.mode===d&&this._initListen(t.el,!0),this.TargetQueue.push(t)),this.TargetIndex}_removeListenerTarget(e){this.TargetQueue.forEach(((t,r)=>{t.el===e&&(t.childrenCount--,t.childrenCount||(this._initListen(t.el,!1),this.TargetQueue.splice(r,1),t=null))}))}_initListen(e,t){this.options.listenEvents.forEach((r=>g[t?"on":"off"](e,r,this.lazyLoadHandler)))}_initEvent(){this.Event={listeners:{loading:[],loaded:[],error:[]}},this.$on=(e,t)=>{this.Event.listeners[e]||(this.Event.listeners[e]=[]),this.Event.listeners[e].push(t)},this.$once=(e,t)=>{const r=this;this.$on(e,(function i(){r.$off(e,i),t.apply(r,arguments)}))},this.$off=(e,t)=>{if(t)c(this.Event.listeners[e],t);else{if(!this.Event.listeners[e])return;this.Event.listeners[e].length=0}},this.$emit=(e,t,r)=>{this.Event.listeners[e]&&this.Event.listeners[e].forEach((e=>e(t,r)))}}_lazyLoadHandler(){const e=[];this.ListenerQueue.forEach(((t,r)=>{t.el&&t.el.parentNode&&!t.state.loaded||e.push(t);t.checkInView()&&(t.state.loaded||t.load())})),e.forEach((e=>{c(this.ListenerQueue,e),e.$destroy&&e.$destroy()}))}_initIntersectionObserver(){l&&(this._observer=new IntersectionObserver(this._observerHandler.bind(this),this.options.observerOptions),this.ListenerQueue.length&&this.ListenerQueue.forEach((e=>{this._observer.observe(e.el)})))}_observerHandler(e){e.forEach((e=>{e.isIntersecting&&this.ListenerQueue.forEach((t=>{if(t.el===e.target){if(t.state.loaded)return this._observer.unobserve(t.el);t.load()}}))}))}_elRenderer(e,t,r){if(!e.el)return;const{el:i,bindType:s}=e;let o;switch(t){case"loading":o=e.loading;break;case"error":o=e.error;break;default:o=e.src}if(s?i.style[s]='url("'+o+'")':i.getAttribute("src")!==o&&i.setAttribute("src",o),i.setAttribute("lazy",t),this.$emit(t,e,r),this.options.adapter[t]&&this.options.adapter[t](e,this.options),this.options.dispatchEvent){const r=new CustomEvent(t,{detail:e});i.dispatchEvent(r)}}_valueFormatter(e){return"object"==typeof e?(e.src||this.options.silent||console.error("Vue Lazyload warning: miss src with "+e),{src:e.src,loading:e.loading||this.options.loading,error:e.error||this.options.error,cors:this.options.cors}):{src:e,loading:this.options.loading,error:this.options.error,cors:this.options.cors}}}const I=(e,r)=>{let i=t.reactive({});return{rect:i,checkInView:()=>(i=e.value.getBoundingClientRect(),a&&i.top<window.innerHeight*r&&i.bottom>0&&i.left<window.innerWidth*r&&i.right>0)}};class T{constructor(e){this.lazy=e,e.lazyContainerMananger=this,this._queue=[]}bind(e,t,r){const i=new O(e,t,r,this.lazy);this._queue.push(i)}update(e,t,r){const i=this._queue.find((t=>t.el===e));i&&i.update(e,t)}unbind(e,t,r){const i=this._queue.find((t=>t.el===e));i&&(i.clear(),c(this._queue,i))}}const x={selector:"img",error:"",loading:""};class O{constructor(e,t,r,i){this.el=e,this.vnode=r,this.binding=t,this.options={},this.lazy=i,this._queue=[],this.update(e,t)}update(e,t){this.el=e,this.options=n({},x,t.value);this.getImgs().forEach((e=>{this.lazy.add(e,n({},this.binding,{value:{src:e.getAttribute("data-src")||e.dataset.src,error:e.getAttribute("data-error")||e.dataset.error||this.options.error,loading:e.getAttribute("data-loading")||e.dataset.loading||this.options.loading}}),this.vnode)}))}getImgs(){return Array.from(this.el.querySelectorAll(this.options.selector))}clear(){this.getImgs().forEach((e=>this.lazy.remove(e))),this.vnode=null,this.binding=null,this.lazy=null}}var $=e=>t.defineComponent({setup(r,{slots:i}){const s=t.ref(),o=t.reactive({src:"",error:"",loading:"",attempt:e.options.attempt}),n=t.reactive({loaded:!1,error:!1,attempt:0}),{rect:a,checkInView:l}=I(s,e.options.preLoad),d=t.ref(""),h=(t=y)=>{if(n.attempt>o.attempt-1&&n.error)return e.options.silent||console.log(`VueLazyload log: ${o.src} tried too more than ${o.attempt} times`),t();const r=o.src;v({src:r},(({src:e})=>{d.value=e,n.loaded=!0}),(()=>{n.attempt++,d.value=o.error,n.error=!0}))},c=t.computed((()=>({el:s.value,rect:a,checkInView:l,load:h,state:n})));t.onMounted((()=>{e.addLazyBox(c.value),e.lazyLoadHandler()})),t.onUnmounted((()=>{e.removeComponent(c.value)}));return t.watch((()=>r.src),(()=>{(()=>{const{src:t,loading:i,error:s}=e._valueFormatter(r.src);n.loaded=!1,o.src=t,o.error=s,o.loading=i,d.value=o.loading})(),e.addLazyBox(c.value),e.lazyLoadHandler()}),{immediate:!0}),()=>{var e;return t.createVNode(r.tag||"img",{src:d.value,ref:s},[null===(e=i.default)||void 0===e?void 0:e.call(i)])}}}),B={install(e,r={}){const i=new z(r),s=new T(i);if(Number(e.version.split(".")[0])<3)return new Error("Vue version at least 3.0");e.config.globalProperties.$Lazyload=i,e.provide("Lazyload",i),r.lazyComponent&&e.component("lazy-component",(e=>t.defineComponent({props:{tag:{type:String,default:"div"}},emits:["show"],setup(r,{emit:i,slots:s}){const o=t.ref(),n=t.reactive({loaded:!1,error:!1,attempt:0}),a=t.ref(!1),{rect:l,checkInView:d}=I(o,e.options.preLoad),h=()=>{a.value=!0,n.loaded=!0,i("show",a.value)},c=t.computed((()=>({el:o.value,rect:l,checkInView:d,load:h,state:n})));return t.onMounted((()=>{e.addLazyBox(c.value),e.lazyLoadHandler()})),t.onUnmounted((()=>{e.removeComponent(c.value)})),()=>{var e;return t.createVNode(r.tag,{ref:o},[a.value&&(null===(e=s.default)||void 0===e?void 0:e.call(s))])}}}))(i)),r.lazyImage&&e.component("lazy-image",$(i)),e.directive("lazy",{beforeMount:i.add.bind(i),beforeUpdate:i.update.bind(i),updated:i.lazyLoadHandler.bind(i),unmounted:i.remove.bind(i)}),e.directive("lazy-container",{beforeMount:s.bind.bind(s),updated:s.update.bind(s),unmounted:s.unbind.bind(s)})}};e.default=B,Object.defineProperty(e,"__esModule",{value:!0})})); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
27
114069
31
2692
3
2