vant
Version:
Mobile UI Components built on Vue
236 lines (235 loc) • 6.03 kB
JavaScript
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(
`[ /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(
`[ /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;
}
}