feat: add @vant/lazyload pacakge
This commit is contained in:
@@ -0,0 +1,347 @@
|
||||
const inBrowser = typeof window !== 'undefined' && window !== null;
|
||||
|
||||
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() {
|
||||
return this.intersectionRatio > 0;
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export const hasIntersectionObserver = checkIntersectionObserver();
|
||||
|
||||
export const modeType = {
|
||||
event: 'event',
|
||||
observer: 'observer',
|
||||
};
|
||||
|
||||
// CustomEvent polyfill
|
||||
const CustomEvent = (function () {
|
||||
if (!inBrowser) return;
|
||||
if (typeof window.CustomEvent === 'function') return window.CustomEvent;
|
||||
function CustomEvent(event, params) {
|
||||
params = params || { bubbles: false, cancelable: false, detail: undefined };
|
||||
const evt = document.createEvent('CustomEvent');
|
||||
evt.initCustomEvent(
|
||||
event,
|
||||
params.bubbles,
|
||||
params.cancelable,
|
||||
params.detail
|
||||
);
|
||||
return evt;
|
||||
}
|
||||
CustomEvent.prototype = window.Event.prototype;
|
||||
return CustomEvent;
|
||||
})();
|
||||
|
||||
function remove(arr, item) {
|
||||
if (!arr.length) return;
|
||||
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 container = el.parentNode;
|
||||
const containerWidth = container.offsetWidth * scale;
|
||||
|
||||
let spaceIndex;
|
||||
let tmpSrc;
|
||||
let tmpWidth;
|
||||
|
||||
options = options.trim().split(',');
|
||||
|
||||
const result = 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
|
||||
);
|
||||
}
|
||||
return [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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
} catch (err) {
|
||||
support = false;
|
||||
}
|
||||
|
||||
return support;
|
||||
}
|
||||
|
||||
function throttle(action, delay) {
|
||||
let timeout = null;
|
||||
let lastRun = 0;
|
||||
return function (...args) {
|
||||
if (timeout) {
|
||||
return;
|
||||
}
|
||||
const elapsed = Date.now() - lastRun;
|
||||
const runCallback = () => {
|
||||
lastRun = Date.now();
|
||||
timeout = false;
|
||||
action.apply(this, args);
|
||||
};
|
||||
if (elapsed >= delay) {
|
||||
runCallback();
|
||||
} else {
|
||||
timeout = setTimeout(runCallback, delay);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function testSupportsPassive() {
|
||||
if (!inBrowser) return;
|
||||
let support = false;
|
||||
try {
|
||||
const opts = Object.defineProperty({}, 'passive', {
|
||||
// eslint-disable-next-line getter-return
|
||||
get() {
|
||||
support = true;
|
||||
},
|
||||
});
|
||||
window.addEventListener('test', null, opts);
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
return support;
|
||||
}
|
||||
|
||||
const supportsPassive = testSupportsPassive();
|
||||
|
||||
const _ = {
|
||||
on(el, type, func, capture = false) {
|
||||
if (supportsPassive) {
|
||||
el.addEventListener(type, func, {
|
||||
capture,
|
||||
passive: true,
|
||||
});
|
||||
} else {
|
||||
el.addEventListener(type, func, capture);
|
||||
}
|
||||
},
|
||||
off(el, type, func, capture = false) {
|
||||
el.removeEventListener(type, func, capture);
|
||||
},
|
||||
};
|
||||
|
||||
const loadImageAsync = (item, resolve, reject) => {
|
||||
const 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);
|
||||
};
|
||||
};
|
||||
|
||||
const style = (el, 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')
|
||||
);
|
||||
};
|
||||
|
||||
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 (!parent.parentNode) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (/(scroll|auto)/.test(overflow(parent))) {
|
||||
return parent;
|
||||
}
|
||||
|
||||
parent = parent.parentNode;
|
||||
}
|
||||
|
||||
return window;
|
||||
};
|
||||
|
||||
function isObject(obj) {
|
||||
return obj !== null && typeof obj === 'object';
|
||||
}
|
||||
|
||||
function ArrayFrom(arrLike) {
|
||||
const 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();
|
||||
}
|
||||
}
|
||||
|
||||
free() {
|
||||
this._caches.shift();
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
ImageCache,
|
||||
inBrowser,
|
||||
CustomEvent,
|
||||
remove,
|
||||
some,
|
||||
find,
|
||||
noop,
|
||||
ArrayFrom,
|
||||
_,
|
||||
isObject,
|
||||
throttle,
|
||||
supportWebp,
|
||||
getDPR,
|
||||
scrollParent,
|
||||
loadImageAsync,
|
||||
getBestSelectionFromSrcset,
|
||||
};
|
||||
Reference in New Issue
Block a user