UNPKG

vue-app-sdk

Version:
247 lines (246 loc) 7.61 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); import { resolveComponentNameByRoute } from "../../utils/index2.js"; import "../../vendors/nice-fns/dist/compactObject.js"; import "../../vendors/nice-fns/dist/pascalCase.js"; import { ref, toValue, isRef, watch, shallowRef, nextTick } from "vue"; import "../../vendors/easy-hookable/dist/callers.js"; import "../../vendors/easy-hookable/dist/ContextHelper.js"; import { NavigationDirection } from "../../core/Router.js"; import "vue-router"; import "../Tabs/Tabs.js"; import isFunction from "../../vendors/lodash-es/isFunction.js"; import isString from "../../vendors/lodash-es/isString.js"; import once from "../../vendors/lodash-es/once.js"; const KEEP_ALIVE_ID = Symbol("keep alive"); const beforeRouteDefaults = { add: () => true, remove: () => true }; class KeepAlive { constructor(options = {}) { __publicField(this, "id", KEEP_ALIVE_ID); /** * 缓存的组件名称列表 */ __publicField(this, "_values", shallowRef(/* @__PURE__ */ new Set())); /** * 是否自动模式 */ __publicField(this, "_isAuto"); /** * 缓存保鲜定时器 */ __publicField(this, "_staleTimer", null); /** * 缓存时间记录 */ __publicField(this, "_timeRecord", {}); /** * 更新缓存记录时间 */ __publicField(this, "_updateTime", (value) => { this._timeRecord[value] = Date.now(); }); /** * 移除缓存时间记录 */ __publicField(this, "_removeTime", (value) => { delete this._timeRecord[value]; }); /** * 启动缓存保鲜定时器 */ __publicField(this, "startStaleTimer", () => { const { staleTime } = this.options; if (typeof staleTime !== "number") throw new Error("staleTime must be a number"); if (staleTime <= 0) return; this.stopStaleTimer(); this.clearExpired(); this._staleTimer = setTimeout(this.startStaleTimer, staleTime); }); /** * 停止缓存保鲜定时器 */ __publicField(this, "stopStaleTimer", () => { if (this._staleTimer) { clearTimeout(this._staleTimer); this._staleTimer = null; } }); /** * 清理过期缓存,设置 `options.staleTime > 0` 后有效 */ __publicField(this, "clearExpired", () => { const { staleTime } = this.options; if (typeof staleTime !== "number" || staleTime <= 0) return; const newTimeRecord = {}; const values = []; Object.entries(this._timeRecord).forEach(([key, time]) => { if (Date.now() - time < staleTime) values.push(key); else newTimeRecord[key] = time; }); this._timeRecord = newTimeRecord; this.set(values); }); /** * 切换自动模式 * @param value 状态值 */ __publicField(this, "toggleAuto", (value = !this._isAuto.value) => { this._isAuto.value = value; return value; }); /** * 启用自动模式 */ __publicField(this, "enableAuto", () => { return this.toggleAuto(true); }); /** * 禁用自动模式 */ __publicField(this, "disableAuto", () => { return this.toggleAuto(false); }); /** * 清空缓存列表 */ __publicField(this, "clear", () => { this.set([]); }); /** * 设置缓存的名称列表,会覆盖旧列表 * @param values 缓存名称列表 */ __publicField(this, "set", (values) => { this._values.value = new Set(values); }); __publicField(this, "install", (sdk) => { const collector = once(() => { sdk.hook("sdk:router:navigate", async (direction, to, from) => { if (!this.isAuto) return; if (direction === NavigationDirection.backward) { const needRemoveMatched = from.matched.filter((m) => !to.matched.includes(m)); await Promise.all(needRemoveMatched.map(this.remove)); } await Promise.all(to.matched.map(this.add)); }); }); const unwatch = watch( this._isAuto, (value) => { if (!value) return; nextTick(() => unwatch()); collector(); }, { immediate: true } ); sdk.hook("sdk:cleanup", this.clear); return () => { unwatch(); this.stopStaleTimer(); }; }); this.options = options; const { autoCollectAndClean = true } = options; this._isAuto = ref(toValue(autoCollectAndClean)); if (isRef(autoCollectAndClean) || isFunction(autoCollectAndClean)) watch(autoCollectAndClean, this.toggleAuto); this.add = this.add.bind(this); this.remove = this.remove.bind(this); this.refresh = this.refresh.bind(this); if (options.staleTime != null) this.startStaleTimer(); } /** * 缓存的组件名称列表 * @readonly */ get values() { return [...this._values.value]; } /** * 是否自动模式 * @readonly */ get isAuto() { return this._isAuto.value; } add(nameOrRoute) { if (!nameOrRoute) return; const values = this._values.value; if (isString(nameOrRoute)) { if (!values.has(nameOrRoute)) { values.add(nameOrRoute); this._updateTime(nameOrRoute); this.set(this.values); } } else if ("components" in nameOrRoute) { const { beforeRouteAdd = beforeRouteDefaults.add } = this.options; return Promise.resolve(beforeRouteAdd(nameOrRoute)).then((valid) => { if (!valid) return; return resolveComponentNameByRoute(nameOrRoute).then(this.add); }); } else if ("matched" in nameOrRoute) { return this.add(nameOrRoute.matched.at(-1)); } } remove(nameOrRoute) { if (!nameOrRoute) return; const values = this._values.value; if (isString(nameOrRoute)) { if (values.has(nameOrRoute)) { values.delete(nameOrRoute); this._removeTime(nameOrRoute); this.set(this.values); } } else if ("components" in nameOrRoute) { const beforeRouteRemove = this.options.beforeRouteRemove || beforeRouteDefaults.remove; return Promise.resolve(beforeRouteRemove(nameOrRoute)).then((valid) => { if (!valid) return; return resolveComponentNameByRoute(nameOrRoute).then(this.remove); }); } else if ("matched" in nameOrRoute) { return this.remove(nameOrRoute.matched.at(-1)); } } refresh(nameOrRoute) { if (!nameOrRoute) return; if (isString(nameOrRoute)) { this.remove(nameOrRoute); nextTick(() => { this.add(nameOrRoute); }); } else if ("components" in nameOrRoute) { const { beforeRouteAdd = beforeRouteDefaults.add, beforeRouteRemove = beforeRouteDefaults.remove } = this.options; return Promise.all([beforeRouteAdd(nameOrRoute), beforeRouteRemove(nameOrRoute)]).then((results) => results.every(Boolean)).then((valid) => { if (!valid) return; return resolveComponentNameByRoute(nameOrRoute).then(this.refresh); }); } else if ("matched" in nameOrRoute) { return this.refresh(nameOrRoute.matched.at(-1)); } } } export { KEEP_ALIVE_ID, KeepAlive };