UNPKG

keep-alive-iframe

Version:

A Vue component for managing iframe lifecycle with keep-alive functionality

322 lines (321 loc) 9.47 kB
var H = Object.defineProperty; var U = (o, e, t) => e in o ? H(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t; var d = (o, e, t) => U(o, typeof e != "symbol" ? e + "" : e, t); import { defineComponent as b, useTemplateRef as T, ref as z, watch as C, onActivated as j, onDeactivated as B, onMounted as K, onUnmounted as X, createElementBlock as Z, openBlock as _, renderSlot as x, createCommentVNode as D, createElementVNode as v, normalizeStyle as O } from "vue"; import { useResizeObserver as N, useThrottleFn as V } from "@vueuse/core"; class n { // 最大缓存数量 static updateLastUsed(e) { const t = this.frameMap.get(e); t && (t.lastUsed = Date.now()); } static enforceCacheLimit() { if (this.frameMap.size <= this.MAX_CACHE_SIZE) return; const e = Array.from(this.frameMap.entries()).sort(([, t], [, i]) => t.lastUsed - i.lastUsed); for (; this.frameMap.size > this.MAX_CACHE_SIZE; ) { const [t] = e.shift(); this.destroy(t); } } static create(e) { const { uid: t } = e, i = this.get(t); i && i.destroy(); const r = new P(e); return this.frameMap.set(t, { frame: r, lastUsed: Date.now() }), this.enforceCacheLimit(), r; } static destroy(e) { const t = this.frameMap.get(e); t && (t.frame.destroy(), this.frameMap.delete(e)); } static show(e) { const t = this.frameMap.get(e); t && (t.frame.show(), this.updateLastUsed(e)); } static hide(e) { const t = this.frameMap.get(e); t && (t.frame.hide(), this.updateLastUsed(e)); } static resize(e, t) { const i = this.frameMap.get(e); i && (i.frame.resize(t), this.updateLastUsed(e)); } static update(e, t) { const i = this.frameMap.get(e); i && (i.frame.update(t), this.updateLastUsed(e)); } static get(e) { const t = this.frameMap.get(e); if (t) return this.updateLastUsed(e), t.frame; } static clear() { this.frameMap.forEach((e) => e.frame.destroy()), this.frameMap.clear(); } // 设置最大缓存数量 static setMaxCacheSize(e) { if (e < 1) { A("缓存大小必须大于0"); return; } this.MAX_CACHE_SIZE = e, this.enforceCacheLimit(); } } d(n, "frameMap", /* @__PURE__ */ new Map()), d(n, "MAX_CACHE_SIZE", 10); class P { constructor(e) { d(this, "el", null); d(this, "options"); d(this, "originalRect", { width: 0, height: 0, top: 0, left: 0 }); d(this, "scrollHandler", null); this.options = e, this.init(); } init() { const { src: e, zIndex: t, attrs: i, onLoaded: r, onError: l, keepAlive: a, container: f, parentContainer: p } = this.options; if (!e) { A("请填写iframe的src"); return; } try { this.el = document.createElement("iframe"), this.el.src = e, this.el.style.setProperty("z-index", t.toString()), this.el.classList.add("keep-alive-frame"), r && (this.el.onload = r), l && (this.el.onerror = l), this.setAttrs(i), this.resize(this.options), a ? (document.body.appendChild(this.el), p && this.addScrollListener(p)) : f && f.appendChild(this.el); } catch (h) { A(`初始化iframe失败: ${h instanceof Error ? h.message : String(h)}`); } } resize(e) { if (!this.el) return; const { left: t, top: i, width: r, height: l } = e; if (this.originalRect = { left: t, top: i, width: r, height: l }, this.options.keepAlive) if (this.options.parentContainer) { const a = this.options.parentContainer.scrollTop, f = this.options.parentContainer.scrollLeft; this.setStyle({ position: "fixed", left: `${t - f}px`, top: `${i - a}px`, width: `${r}px`, height: `${l}px` }); } else this.setStyle({ position: "fixed", left: `${t}px`, top: `${i}px`, width: `${r}px`, height: `${l}px` }); else this.setStyle({ width: "100%", height: "100%" }); } destroy() { this.el && (this.el.onload = null, this.el.onerror = null, this.el.remove(), this.el = null, this.scrollHandler && this.options.parentContainer && (this.options.parentContainer.removeEventListener("scroll", this.scrollHandler), this.scrollHandler = null)); } show() { this.el && this.el.classList.remove("is-hidden"); } hide() { this.el && this.el.classList.add("is-hidden"); } update(e) { this.el && (this.el.src = e); } setStyle(e) { this.el && Object.assign(this.el.style, e); } setAttrs(e) { this.el && Object.entries(e).forEach(([t, i]) => { this.el && this.el.setAttribute(t, String(i)); }); } addScrollListener(e) { this.el && (this.scrollHandler = () => { if (!this.el || !this.options.keepAlive) return; const t = e.scrollTop, i = e.scrollLeft; this.setStyle({ position: "fixed", left: `${this.originalRect.left - i}px`, top: `${this.originalRect.top - t}px`, width: `${this.originalRect.width}px`, height: `${this.originalRect.height}px` }); }, e.addEventListener("scroll", this.scrollHandler)); } getEl() { return this.el; } } let q = 0; function G() { return `iframe_${q++}`; } function A(o) { console.error(`[KeepAliveFrame]: ${o}`); } const Y = /* @__PURE__ */ b({ __name: "KeepAliveFrame", props: { src: {}, keepAlive: { type: Boolean, default: !0 }, iframeAttrs: {}, maxCacheSize: { default: 10 }, parentContainer: {}, zIndex: { default: 0 } }, emits: ["load", "error", "activated", "deactivated", "destroy", "resize", "cacheHit", "cacheMiss"], setup(o, { expose: e, emit: t }) { const i = o, r = t, l = T("iframeContainerRef"), a = G(), f = z(!1), p = z(!1); let h = !1, u = !1; function w() { !n.get(a) && i.src && m(); } e({ getFrame: () => { var s; return (s = n.get(a)) == null ? void 0 : s.getEl(); } }), N( l, V(S, 300, !0) ), C(l, (s) => { i.src && s ? m() : g(); }), C(() => i.src, (s) => { M(s); }), C(() => i.maxCacheSize, (s) => { n.setMaxCacheSize(s); }), j(() => { if (u = !0, i.keepAlive) { w(), L(), r("activated"); return; } m(), r("activated"); }), B(() => { if (u = !1, i.keepAlive) { E(), r("deactivated"); return; } g(), r("deactivated"), h = !1; }), K(() => { u = !0, w(), n.setMaxCacheSize(i.maxCacheSize); }), X(() => { g(), h = !1, u = !1, r("destroy"); }); function m() { g(), f.value = !0, p.value = !1; const { width: s, height: c, left: F, top: I } = y(), R = n.get(a); r(R ? "cacheHit" : "cacheMiss"), n.create({ uid: a, width: s, height: c, left: F, top: I, src: i.src, zIndex: i.zIndex || 0, attrs: i.iframeAttrs || {}, onLoaded: k, onError: $, keepAlive: i.keepAlive, container: i.keepAlive ? void 0 : l.value, parentContainer: i.parentContainer }); } function g() { n.destroy(a); } function M(s) { n.get(a) ? n.update(a, s) : m(); } function L() { n.get(a) ? n.show(a) : m(); } function E() { n.get(a) && n.hide(a); } function S() { n.resize(a, y()), h && u && r("resize", y()); } function k(s) { f.value = !1, h = !0, r("load", s); } function $(s) { f.value = !1, p.value = !0, r("error", s); } function y() { var s; return ((s = l.value) == null ? void 0 : s.getBoundingClientRect()) || { width: 0, height: 0, top: 0, left: 0 }; } return (s, c) => (_(), Z( "div", { ref_key: "iframeContainerRef", ref: l, class: "relative w-full h-full", role: "keep-alive-frame-container" }, [ s.src ? f.value ? x(s.$slots, "loading", { key: 1, zIndex: s.zIndex + 1 }, () => [ v( "div", { class: "w-full h-full absolute left-0 top-0 inset-0 bg-white/80 backdrop-blur-sm flex items-center justify-center", style: O({ zIndex: s.zIndex + 1 }) }, c[1] || (c[1] = [ v( "div", { class: "keep-alive-loading-spinner" }, null, -1 /* HOISTED */ ) ]), 4 /* STYLE */ ) ]) : p.value ? x(s.$slots, "error", { key: 2 }, () => [ c[2] || (c[2] = v( "div", { class: "flex justify-center items-center w-full h-full text-gray-500" }, " 出错了! ", -1 /* HOISTED */ )) ]) : D("v-if", !0) : x(s.$slots, "empty", { key: 0 }, () => [ c[0] || (c[0] = v( "div", { class: "flex justify-center items-center w-full h-full text-gray-500" }, " 请输入iframe的地址 ", -1 /* HOISTED */ )) ]) ], 512 /* NEED_PATCH */ )); } }); export { n as FrameManager, P as KAliveFrame, Y as KeepAliveFrame, Y as default, G as generateId }; //# sourceMappingURL=keep-alive-iframe.es.js.map