@eternalheart/vue-file-preview 1.3.13 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/FilePreviewContent.vue.d.ts +3 -0
- package/lib/FilePreviewContent.vue.d.ts.map +1 -1
- package/lib/FilePreviewEmbed.vue.d.ts +5 -0
- package/lib/FilePreviewEmbed.vue.d.ts.map +1 -1
- package/lib/FilePreviewModal.vue.d.ts.map +1 -1
- package/lib/chunks/{RendererError.vue_vue_type_script_setup_true_lang-CbgZBSDr.mjs → RendererError.vue_vue_type_script_setup_true_lang-BNoENOWX.mjs} +9 -9
- package/lib/chunks/RendererError.vue_vue_type_script_setup_true_lang-BNoENOWX.mjs.map +1 -0
- package/lib/chunks/index-8ETACZ6T.mjs +267 -0
- package/lib/chunks/index-8ETACZ6T.mjs.map +1 -0
- package/lib/chunks/{index-DyipSoKh.mjs → index-B-LW-GJO.mjs} +24 -21
- package/lib/chunks/index-B-LW-GJO.mjs.map +1 -0
- package/lib/chunks/{index-Cjnw238n.mjs → index-BT9hXA6r.mjs} +3 -3
- package/lib/chunks/{index-Cjnw238n.mjs.map → index-BT9hXA6r.mjs.map} +1 -1
- package/lib/chunks/{index-CyrFxdIJ.mjs → index-BcKI75RW.mjs} +4 -4
- package/lib/chunks/{index-CyrFxdIJ.mjs.map → index-BcKI75RW.mjs.map} +1 -1
- package/lib/chunks/{index-Ctd0JQ6K.mjs → index-By6vGdnK.mjs} +3 -3
- package/lib/chunks/{index-Ctd0JQ6K.mjs.map → index-By6vGdnK.mjs.map} +1 -1
- package/lib/chunks/{index-BHi1WRQZ.mjs → index-C-Mu0fvH.mjs} +3 -3
- package/lib/chunks/{index-BHi1WRQZ.mjs.map → index-C-Mu0fvH.mjs.map} +1 -1
- package/lib/chunks/{index-DT9dPz8I.mjs → index-CGSq7-Q-.mjs} +3 -3
- package/lib/chunks/{index-DT9dPz8I.mjs.map → index-CGSq7-Q-.mjs.map} +1 -1
- package/lib/chunks/{index-DTtHrdBl.mjs → index-CWpU8prZ.mjs} +11 -11
- package/lib/chunks/index-CWpU8prZ.mjs.map +1 -0
- package/lib/chunks/index-CYa_XneH.mjs +303 -0
- package/lib/chunks/index-CYa_XneH.mjs.map +1 -0
- package/lib/chunks/{index-CYt6tpQC.mjs → index-CbJkkdEB.mjs} +9 -9
- package/lib/chunks/index-CbJkkdEB.mjs.map +1 -0
- package/lib/chunks/{index-DEoR7aDN.mjs → index-CoITLoYL.mjs} +3 -3
- package/lib/chunks/{index-DEoR7aDN.mjs.map → index-CoITLoYL.mjs.map} +1 -1
- package/lib/chunks/{index-Oxwizt6-.mjs → index-D9QQL7U6.mjs} +605 -557
- package/lib/chunks/index-D9QQL7U6.mjs.map +1 -0
- package/lib/chunks/{index-BvegaxQF.mjs → index-DAdO2lkI.mjs} +32 -32
- package/lib/chunks/index-DAdO2lkI.mjs.map +1 -0
- package/lib/chunks/{index-GGGDPwxX.mjs → index-DGqDJMot.mjs} +3 -3
- package/lib/chunks/{index-GGGDPwxX.mjs.map → index-DGqDJMot.mjs.map} +1 -1
- package/lib/chunks/{index-DIe0vHlt.mjs → index-DTyG1Wzp.mjs} +8 -8
- package/lib/chunks/index-DTyG1Wzp.mjs.map +1 -0
- package/lib/chunks/{index-Dw1U4YqT.mjs → index-DglMeKJM.mjs} +36 -38
- package/lib/chunks/{index-Dw1U4YqT.mjs.map → index-DglMeKJM.mjs.map} +1 -1
- package/lib/chunks/{index-B2lqsdp7.mjs → index-OOoaYpkl.mjs} +3 -3
- package/lib/chunks/{index-B2lqsdp7.mjs.map → index-OOoaYpkl.mjs.map} +1 -1
- package/lib/chunks/{index-DBw8tvyb.mjs → index-jcgLzyDR.mjs} +4 -4
- package/lib/chunks/{index-DBw8tvyb.mjs.map → index-jcgLzyDR.mjs.map} +1 -1
- package/lib/chunks/{index-BTW1xwB9.mjs → index-nFIiu1lA.mjs} +3 -3
- package/lib/chunks/{index-BTW1xwB9.mjs.map → index-nFIiu1lA.mjs.map} +1 -1
- package/lib/index.cjs +40 -32
- package/lib/index.cjs.map +1 -1
- package/lib/index.css +1 -1
- package/lib/index.mjs +1 -1
- package/lib/renderers/Audio/index.vue.d.ts.map +1 -1
- package/lib/renderers/Docx/index.vue.d.ts.map +1 -1
- package/lib/renderers/Epub/index.vue.d.ts.map +1 -1
- package/lib/renderers/Markdown/index.vue.d.ts.map +1 -1
- package/lib/renderers/Pdf/index.vue.d.ts +3 -0
- package/lib/renderers/Pdf/index.vue.d.ts.map +1 -1
- package/lib/renderers/Pdf/toolbar.d.ts +5 -0
- package/lib/renderers/Pdf/toolbar.d.ts.map +1 -1
- package/lib/renderers/RendererError.vue.d.ts.map +1 -1
- package/lib/renderers/Subtitle/index.vue.d.ts.map +1 -1
- package/lib/renderers/Text/index.vue.d.ts.map +1 -1
- package/lib/renderers/Xml/index.vue.d.ts.map +1 -1
- package/package.json +1 -1
- package/lib/chunks/RendererError.vue_vue_type_script_setup_true_lang-CbgZBSDr.mjs.map +0 -1
- package/lib/chunks/index-BvegaxQF.mjs.map +0 -1
- package/lib/chunks/index-CYt6tpQC.mjs.map +0 -1
- package/lib/chunks/index-DIe0vHlt.mjs.map +0 -1
- package/lib/chunks/index-DTtHrdBl.mjs.map +0 -1
- package/lib/chunks/index-DX_NBPzS.mjs +0 -248
- package/lib/chunks/index-DX_NBPzS.mjs.map +0 -1
- package/lib/chunks/index-DyipSoKh.mjs.map +0 -1
- package/lib/chunks/index-Oxwizt6-.mjs.map +0 -1
- package/lib/chunks/index-Zwl5J-Uw.mjs +0 -166
- package/lib/chunks/index-Zwl5J-Uw.mjs.map +0 -1
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { defineComponent as I, ref as w, onMounted as W, watch as S, onBeforeUnmount as $, openBlock as x, createElementBlock as b, createBlock as A, createCommentVNode as k, createElementVNode as R, withDirectives as F, vShow as N, toDisplayString as B, nextTick as O } from "vue";
|
|
2
|
-
import { B as U, u as Z } from "./index-Oxwizt6-.mjs";
|
|
3
|
-
import * as D from "pdfjs-dist/build/pdf.mjs";
|
|
4
|
-
import { _ as M } from "./RendererError.vue_vue_type_script_setup_true_lang-CbgZBSDr.mjs";
|
|
5
|
-
const G = {
|
|
6
|
-
key: 1,
|
|
7
|
-
class: "vfp-flex vfp-items-center vfp-justify-center vfp-min-h-screen"
|
|
8
|
-
}, J = { class: "pdf-pages vfp-flex vfp-flex-col vfp-gap-4" }, K = {
|
|
9
|
-
key: 2,
|
|
10
|
-
class: "vfp-sticky vfp-bottom-2 md:vfp-bottom-4 vfp-mt-4 md:vfp-mt-8 vfp-bg-surface-nav-hover vfp-backdrop-blur-xl vfp-text-fg-primary vfp-px-4 vfp-py-2 md:vfp-px-6 md:vfp-py-3 vfp-rounded-full vfp-text-xs md:vfp-text-sm vfp-font-medium vfp-shadow-2xl vfp-border vfp-border-line-weak"
|
|
11
|
-
}, ee = /* @__PURE__ */ I({
|
|
12
|
-
components: {
|
|
13
|
-
RendererError: M
|
|
14
|
-
},
|
|
15
|
-
__name: "index",
|
|
16
|
-
props: {
|
|
17
|
-
url: {},
|
|
18
|
-
zoom: {},
|
|
19
|
-
currentPage: {}
|
|
20
|
-
},
|
|
21
|
-
emits: ["pageChange", "totalPagesChange", "pageWidthChange"],
|
|
22
|
-
setup(T, { emit: z }) {
|
|
23
|
-
U(D);
|
|
24
|
-
const u = T, g = z, { t: L } = Z(), c = w(0), f = w(null), l = w(null);
|
|
25
|
-
let s = null;
|
|
26
|
-
const i = /* @__PURE__ */ new Map();
|
|
27
|
-
let a = null;
|
|
28
|
-
const V = async (e, t) => {
|
|
29
|
-
if (!s) return;
|
|
30
|
-
const n = i.get(e);
|
|
31
|
-
if (!(!n || n.rendering)) {
|
|
32
|
-
n.rendering = !0;
|
|
33
|
-
try {
|
|
34
|
-
const r = await s.getPage(e), p = r.getViewport({ scale: t }), o = document.createElement("canvas");
|
|
35
|
-
o.width = p.width, o.height = p.height, o.style.maxWidth = "100%", o.style.height = "auto", o.style.borderRadius = "0", o.style.display = "block", o.style.boxShadow = "0 25px 50px -12px rgba(0,0,0,0.25)", o.style.filter = "brightness(0.95) contrast(1.05)";
|
|
36
|
-
const m = o.getContext("2d");
|
|
37
|
-
if (!m) return;
|
|
38
|
-
const h = r.render({ canvasContext: m, viewport: p });
|
|
39
|
-
if (n.renderTask = h, await h.promise, e === 1) {
|
|
40
|
-
const y = r.getViewport({ scale: 1 });
|
|
41
|
-
g("pageWidthChange", y.width);
|
|
42
|
-
}
|
|
43
|
-
n.element.innerHTML = "", n.element.appendChild(o);
|
|
44
|
-
const d = document.createElement("div");
|
|
45
|
-
d.textContent = String(e), d.style.cssText = "position:absolute;top:8px;right:8px;background:rgba(0,0,0,0.6);backdrop-filter:blur(4px);color:white;font-size:12px;padding:4px 12px;border-radius:9999px;", n.element.appendChild(d), n.rendered = !0;
|
|
46
|
-
} catch (r) {
|
|
47
|
-
(r == null ? void 0 : r.name) !== "RenderingCancelledException" && console.error(`渲染页面 ${e} 失败:`, r);
|
|
48
|
-
} finally {
|
|
49
|
-
n.rendering = !1, n.renderTask = null;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}, C = (e) => {
|
|
53
|
-
const t = i.get(e);
|
|
54
|
-
if (!t) return;
|
|
55
|
-
t.renderTask && (t.renderTask.cancel(), t.renderTask = null);
|
|
56
|
-
const n = t.element.querySelector("canvas");
|
|
57
|
-
if (n) {
|
|
58
|
-
const r = n.getContext("2d");
|
|
59
|
-
r && r.clearRect(0, 0, n.width, n.height), n.remove();
|
|
60
|
-
}
|
|
61
|
-
t.element.innerHTML = "", t.rendered = !1, t.rendering = !1;
|
|
62
|
-
}, H = async () => {
|
|
63
|
-
if (!s || !l.value) return;
|
|
64
|
-
const e = l.value.querySelector(".pdf-pages");
|
|
65
|
-
if (e) {
|
|
66
|
-
e.innerHTML = "", i.clear();
|
|
67
|
-
for (let t = 1; t <= c.value; t++) {
|
|
68
|
-
const n = document.createElement("div");
|
|
69
|
-
n.style.cssText = "position:relative;display:flex;justify-content:center;min-height:800px;", n.dataset.pageNumber = String(t), e.appendChild(n), i.set(t, {
|
|
70
|
-
element: n,
|
|
71
|
-
rendered: !1,
|
|
72
|
-
rendering: !1,
|
|
73
|
-
renderTask: null
|
|
74
|
-
}), a && a.observe(n);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}, P = async () => {
|
|
78
|
-
if (f.value = null, c.value = 0, s) {
|
|
79
|
-
try {
|
|
80
|
-
s.destroy();
|
|
81
|
-
} catch {
|
|
82
|
-
}
|
|
83
|
-
s = null;
|
|
84
|
-
}
|
|
85
|
-
try {
|
|
86
|
-
s = await D.getDocument({ url: u.url }).promise, c.value = s.numPages, g("totalPagesChange", s.numPages), g("pageChange", 1), await O(), await H();
|
|
87
|
-
} catch (e) {
|
|
88
|
-
console.error("PDF 加载错误:", e), f.value = L.value("pdf.load_failed");
|
|
89
|
-
}
|
|
90
|
-
}, E = () => {
|
|
91
|
-
if (!l.value || i.size === 0) return;
|
|
92
|
-
const e = l.value, t = e.scrollTop, n = e.clientHeight, r = t + n / 2;
|
|
93
|
-
let p = 1, o = 1 / 0;
|
|
94
|
-
i.forEach((m, h) => {
|
|
95
|
-
const d = m.element.getBoundingClientRect(), y = e.getBoundingClientRect(), q = d.top - y.top + d.height / 2 + t, _ = Math.abs(q - r);
|
|
96
|
-
_ < o && (o = _, p = h);
|
|
97
|
-
}), p !== u.currentPage && g("pageChange", p);
|
|
98
|
-
};
|
|
99
|
-
let v = null;
|
|
100
|
-
const j = () => {
|
|
101
|
-
v && clearTimeout(v), v = window.setTimeout(() => {
|
|
102
|
-
i.forEach((e, t) => {
|
|
103
|
-
e.rendered && C(t);
|
|
104
|
-
}), a && l.value && l.value.querySelector(".pdf-pages") && i.forEach((t) => {
|
|
105
|
-
a == null || a.unobserve(t.element), a == null || a.observe(t.element);
|
|
106
|
-
});
|
|
107
|
-
}, 150);
|
|
108
|
-
};
|
|
109
|
-
return W(() => {
|
|
110
|
-
a = new IntersectionObserver(
|
|
111
|
-
(e) => {
|
|
112
|
-
e.forEach((t) => {
|
|
113
|
-
const n = Number(t.target.getAttribute("data-page-number"));
|
|
114
|
-
if (n)
|
|
115
|
-
if (t.isIntersecting)
|
|
116
|
-
V(n, u.zoom);
|
|
117
|
-
else {
|
|
118
|
-
const r = i.get(n);
|
|
119
|
-
r && r.rendered && C(n);
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
root: l.value,
|
|
125
|
-
rootMargin: "500px 0px",
|
|
126
|
-
threshold: 0
|
|
127
|
-
}
|
|
128
|
-
), P(), l.value && l.value.addEventListener("scroll", E);
|
|
129
|
-
}), S(
|
|
130
|
-
() => u.url,
|
|
131
|
-
(e) => {
|
|
132
|
-
e && P();
|
|
133
|
-
}
|
|
134
|
-
), S(() => u.zoom, j), $(() => {
|
|
135
|
-
if (v && clearTimeout(v), a && (a.disconnect(), a = null), l.value && l.value.removeEventListener("scroll", E), i.forEach((e) => {
|
|
136
|
-
e.renderTask && e.renderTask.cancel();
|
|
137
|
-
}), i.clear(), s) {
|
|
138
|
-
try {
|
|
139
|
-
s.destroy();
|
|
140
|
-
} catch {
|
|
141
|
-
}
|
|
142
|
-
s = null;
|
|
143
|
-
}
|
|
144
|
-
}), (e, t) => (x(), b("div", {
|
|
145
|
-
ref_key: "containerRef",
|
|
146
|
-
ref: l,
|
|
147
|
-
class: "vfp-flex vfp-flex-col vfp-items-center vfp-w-full vfp-h-full vfp-overflow-auto vfp-py-4 md:vfp-py-8 vfp-px-2 md:vfp-px-4"
|
|
148
|
-
}, [
|
|
149
|
-
f.value ? (x(), A(M, {
|
|
150
|
-
key: 0,
|
|
151
|
-
message: f.value
|
|
152
|
-
}, null, 8, ["message"])) : k("", !0),
|
|
153
|
-
!f.value && c.value === 0 ? (x(), b("div", G, [...t[0] || (t[0] = [
|
|
154
|
-
R("div", { class: "vfp-w-12 vfp-h-12 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin" }, null, -1)
|
|
155
|
-
])])) : k("", !0),
|
|
156
|
-
F(R("div", J, null, 512), [
|
|
157
|
-
[N, !f.value && c.value > 0]
|
|
158
|
-
]),
|
|
159
|
-
c.value > 0 ? (x(), b("div", K, " 第 " + B(T.currentPage) + " 页 / 共 " + B(c.value) + " 页 ", 1)) : k("", !0)
|
|
160
|
-
], 512));
|
|
161
|
-
}
|
|
162
|
-
});
|
|
163
|
-
export {
|
|
164
|
-
ee as default
|
|
165
|
-
};
|
|
166
|
-
//# sourceMappingURL=index-Zwl5J-Uw.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index-Zwl5J-Uw.mjs","sources":["../../src/renderers/Pdf/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount, nextTick } from 'vue';\nimport { configurePdfWorker } from '@eternalheart/file-preview-core';\n// @ts-ignore - pdfjs-dist 类型路径\nimport * as pdfjsLib from 'pdfjs-dist/build/pdf.mjs';\nimport { useTranslator } from '../../composables/useTranslator';\nimport RendererError from '../RendererError.vue';\n\n// 在模块加载时配置 PDF.js worker(默认走 CDN)\nconfigurePdfWorker(pdfjsLib);\n\ndefineOptions({\n components: {\n RendererError,\n },\n});\n\ninterface PdfPageProxy {\n getViewport(opts: { scale: number }): { width: number; height: number };\n render(opts: { canvasContext: CanvasRenderingContext2D; viewport: { width: number; height: number } }): {\n promise: Promise<void>;\n cancel(): void;\n };\n}\n\ninterface PdfDocumentProxy {\n numPages: number;\n getPage(pageNumber: number): Promise<PdfPageProxy>;\n destroy(): void;\n}\n\ninterface PageState {\n element: HTMLDivElement;\n rendered: boolean;\n rendering: boolean;\n renderTask: { cancel(): void } | null;\n}\n\nconst props = defineProps<{\n url: string;\n zoom: number;\n currentPage: number;\n}>();\n\nconst emit = defineEmits<{\n (e: 'pageChange', page: number): void;\n (e: 'totalPagesChange', total: number): void;\n (e: 'pageWidthChange', width: number): void;\n}>();\n\nconst { t } = useTranslator();\n\nconst numPages = ref(0);\nconst error = ref<string | null>(null);\nconst containerRef = ref<HTMLDivElement | null>(null);\nlet pdfDoc: PdfDocumentProxy | null = null;\nconst pageStates = new Map<number, PageState>();\nlet observer: IntersectionObserver | null = null;\n\nconst renderPage = async (pageNumber: number, scale: number) => {\n if (!pdfDoc) return;\n const state = pageStates.get(pageNumber);\n if (!state || state.rendering) return;\n\n state.rendering = true;\n\n try {\n const page = await pdfDoc.getPage(pageNumber);\n const viewport = page.getViewport({ scale });\n\n const canvas = document.createElement('canvas');\n canvas.width = viewport.width;\n canvas.height = viewport.height;\n canvas.style.maxWidth = '100%';\n canvas.style.height = 'auto';\n canvas.style.borderRadius = '0';\n canvas.style.display = 'block';\n canvas.style.boxShadow = '0 25px 50px -12px rgba(0,0,0,0.25)';\n canvas.style.filter = 'brightness(0.95) contrast(1.05)';\n\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const renderTask = page.render({ canvasContext: ctx, viewport });\n state.renderTask = renderTask;\n await renderTask.promise;\n\n // 上报第一页原始宽度\n if (pageNumber === 1) {\n const baseViewport = page.getViewport({ scale: 1 });\n emit('pageWidthChange', baseViewport.width);\n }\n\n state.element.innerHTML = '';\n state.element.appendChild(canvas);\n\n // 页码标签\n const label = document.createElement('div');\n label.textContent = String(pageNumber);\n label.style.cssText =\n 'position:absolute;top:8px;right:8px;background:rgba(0,0,0,0.6);backdrop-filter:blur(4px);color:white;font-size:12px;padding:4px 12px;border-radius:9999px;';\n state.element.appendChild(label);\n\n state.rendered = true;\n } catch (err: any) {\n if (err?.name !== 'RenderingCancelledException') {\n console.error(`渲染页面 ${pageNumber} 失败:`, err);\n }\n } finally {\n state.rendering = false;\n state.renderTask = null;\n }\n};\n\nconst clearPageCanvas = (pageNumber: number) => {\n const state = pageStates.get(pageNumber);\n if (!state) return;\n\n // 取消正在进行的渲染\n if (state.renderTask) {\n state.renderTask.cancel();\n state.renderTask = null;\n }\n\n // 清理 canvas,保留占位符\n const canvas = state.element.querySelector('canvas');\n if (canvas) {\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n }\n canvas.remove();\n }\n\n state.element.innerHTML = '';\n state.rendered = false;\n state.rendering = false;\n};\n\nconst initPagePlaceholders = async () => {\n if (!pdfDoc || !containerRef.value) return;\n const wrapper = containerRef.value.querySelector('.pdf-pages') as HTMLDivElement | null;\n if (!wrapper) return;\n\n wrapper.innerHTML = '';\n pageStates.clear();\n\n // 预计算所有页面的高度占位\n for (let i = 1; i <= numPages.value; i++) {\n const pageDiv = document.createElement('div');\n pageDiv.style.cssText = 'position:relative;display:flex;justify-content:center;min-height:800px;';\n pageDiv.dataset.pageNumber = String(i);\n wrapper.appendChild(pageDiv);\n\n pageStates.set(i, {\n element: pageDiv,\n rendered: false,\n rendering: false,\n renderTask: null,\n });\n\n // 使用 IntersectionObserver 监听\n if (observer) {\n observer.observe(pageDiv);\n }\n }\n};\n\nconst loadPdf = async () => {\n error.value = null;\n numPages.value = 0;\n if (pdfDoc) {\n try {\n pdfDoc.destroy();\n } catch {\n // ignore\n }\n pdfDoc = null;\n }\n\n try {\n const loadingTask = pdfjsLib.getDocument({ url: props.url });\n pdfDoc = (await loadingTask.promise) as PdfDocumentProxy;\n numPages.value = pdfDoc.numPages;\n emit('totalPagesChange', pdfDoc.numPages);\n emit('pageChange', 1);\n await nextTick();\n await initPagePlaceholders();\n } catch (err) {\n console.error('PDF 加载错误:', err);\n error.value = t.value('pdf.load_failed');\n }\n};\n\nconst handleScroll = () => {\n if (!containerRef.value || pageStates.size === 0) return;\n\n const container = containerRef.value;\n const scrollTop = container.scrollTop;\n const containerHeight = container.clientHeight;\n const scrollCenter = scrollTop + containerHeight / 2;\n\n let currentVisiblePage = 1;\n let minDistance = Infinity;\n\n pageStates.forEach((state, pageNumber) => {\n const rect = state.element.getBoundingClientRect();\n const containerRect = container.getBoundingClientRect();\n const pageCenter = rect.top - containerRect.top + rect.height / 2 + scrollTop;\n const distance = Math.abs(pageCenter - scrollCenter);\n\n if (distance < minDistance) {\n minDistance = distance;\n currentVisiblePage = pageNumber;\n }\n });\n\n if (currentVisiblePage !== props.currentPage) {\n emit('pageChange', currentVisiblePage);\n }\n};\n\nlet zoomDebounceTimer: number | null = null;\nconst handleZoomChange = () => {\n if (zoomDebounceTimer) {\n clearTimeout(zoomDebounceTimer);\n }\n\n zoomDebounceTimer = window.setTimeout(() => {\n // 清理所有已渲染页面\n pageStates.forEach((state, pageNumber) => {\n if (state.rendered) {\n clearPageCanvas(pageNumber);\n }\n });\n\n // 触发 IntersectionObserver 重新渲染可见页面\n if (observer && containerRef.value) {\n const wrapper = containerRef.value.querySelector('.pdf-pages') as HTMLDivElement | null;\n if (wrapper) {\n pageStates.forEach((state) => {\n observer?.unobserve(state.element);\n observer?.observe(state.element);\n });\n }\n }\n }, 150);\n};\n\nonMounted(() => {\n // 初始化 IntersectionObserver,设置缓冲区为上下 500px\n observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n const pageNumber = Number(entry.target.getAttribute('data-page-number'));\n if (!pageNumber) return;\n\n if (entry.isIntersecting) {\n // 页面进入视口,渲染\n renderPage(pageNumber, props.zoom);\n } else {\n // 页面离开视口较远,清理 canvas\n const state = pageStates.get(pageNumber);\n if (state && state.rendered) {\n clearPageCanvas(pageNumber);\n }\n }\n });\n },\n {\n root: containerRef.value,\n rootMargin: '500px 0px',\n threshold: 0,\n }\n );\n\n loadPdf();\n if (containerRef.value) {\n containerRef.value.addEventListener('scroll', handleScroll);\n }\n});\n\nwatch(\n () => props.url,\n (newUrl) => {\n // 只有 URL 有效时才加载(避免空字符串或已 revoke 的 blob URL)\n if (newUrl) {\n loadPdf();\n }\n }\n);\n\nwatch(() => props.zoom, handleZoomChange);\n\nonBeforeUnmount(() => {\n if (zoomDebounceTimer) {\n clearTimeout(zoomDebounceTimer);\n }\n\n if (observer) {\n observer.disconnect();\n observer = null;\n }\n\n if (containerRef.value) {\n containerRef.value.removeEventListener('scroll', handleScroll);\n }\n\n // 清理所有渲染任务\n pageStates.forEach((state) => {\n if (state.renderTask) {\n state.renderTask.cancel();\n }\n });\n pageStates.clear();\n\n if (pdfDoc) {\n try {\n pdfDoc.destroy();\n } catch {\n // ignore\n }\n pdfDoc = null;\n }\n});\n</script>\n\n<template>\n <div\n ref=\"containerRef\"\n class=\"vfp-flex vfp-flex-col vfp-items-center vfp-w-full vfp-h-full vfp-overflow-auto vfp-py-4 md:vfp-py-8 vfp-px-2 md:vfp-px-4\"\n >\n <RendererError v-if=\"error\" :message=\"error\" />\n\n <div v-if=\"!error && numPages === 0\" class=\"vfp-flex vfp-items-center vfp-justify-center vfp-min-h-screen\">\n <div\n class=\"vfp-w-12 vfp-h-12 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin\"\n />\n </div>\n\n <div v-show=\"!error && numPages > 0\" class=\"pdf-pages vfp-flex vfp-flex-col vfp-gap-4\" />\n\n <div\n v-if=\"numPages > 0\"\n class=\"vfp-sticky vfp-bottom-2 md:vfp-bottom-4 vfp-mt-4 md:vfp-mt-8 vfp-bg-surface-nav-hover vfp-backdrop-blur-xl vfp-text-fg-primary vfp-px-4 vfp-py-2 md:vfp-px-6 md:vfp-py-3 vfp-rounded-full vfp-text-xs md:vfp-text-sm vfp-font-medium vfp-shadow-2xl vfp-border vfp-border-line-weak\"\n >\n 第 {{ currentPage }} 页 / 共 {{ numPages }} 页\n </div>\n </div>\n</template>\n"],"names":["configurePdfWorker","pdfjsLib","props","__props","emit","__emit","t","useTranslator","numPages","ref","error","containerRef","pdfDoc","pageStates","observer","renderPage","pageNumber","scale","state","page","viewport","canvas","ctx","renderTask","baseViewport","label","err","clearPageCanvas","initPagePlaceholders","wrapper","i","pageDiv","loadPdf","nextTick","handleScroll","container","scrollTop","containerHeight","scrollCenter","currentVisiblePage","minDistance","rect","containerRect","pageCenter","distance","zoomDebounceTimer","handleZoomChange","onMounted","entries","entry","watch","newUrl","onBeforeUnmount","_createElementBlock","_createBlock","RendererError","_openBlock","_hoisted_1","_cache","_createElementVNode","_withDirectives","_hoisted_2","_vShow","_hoisted_3","_toDisplayString"],"mappings":"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"}
|