UNPKG

vant

Version:

Mobile UI Components built on Vue

236 lines (235 loc) 6.03 kB
var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var stdin_exports = {}; __export(stdin_exports, { default: () => ReactiveListener }); module.exports = __toCommonJS(stdin_exports); var import_use = require("@vant/use"); var import_util = require("./util"); var import_utils = require("../../utils"); 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.$parent = $parent; this.elRenderer = elRenderer; this.imageCache = imageCache; this.performanceData = { 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); } 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(); } } /* * check el is in view * @return {Boolean} el is in view */ checkInView() { const rect = (0, import_use.useRect)(this.el); return rect.top < window.innerHeight * this.options.preLoad && rect.bottom > this.options.preLoadTop && rect.left < window.innerWidth * this.options.preLoad && rect.right > 0; } /* * listener filter */ filter() { Object.keys(this.options.filter).forEach((key) => { this.options.filter[key](this, this.options); }); } /* * render loading first * @params cb:Function * @return */ renderLoading(cb) { this.state.loading = true; (0, import_util.loadImageAsync)( { src: this.loading, cors: this.cors }, () => { this.render("loading", false); this.state.loading = false; cb(); }, () => { cb(); this.state.loading = false; if (process.env.NODE_ENV !== "production" && !this.options.silent) console.warn( `[@vant/lazyload] load failed with loading image(${this.loading})` ); } ); } /* * try load image and render it * @return */ load(onFinish = import_utils.noop) { if (this.attempt > this.options.attempt - 1 && this.state.error) { if (process.env.NODE_ENV !== "production" && !this.options.silent) { console.log( `[@vant/lazyload] ${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(() => { var _a, _b; this.attempt++; (_b = (_a = this.options.adapter).beforeLoad) == null ? void 0 : _b.call(_a, this, this.options); this.record("loadStart"); (0, import_util.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) / 1e3; } 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; } }