hookehuyr

refactor(PdfViewer): 优化PDF查看器关闭逻辑和资源清理

添加PDF组件引用并实现销毁方法
延迟清理状态确保组件完成内部清理
新增onClose和onDestroy事件通知父组件
...@@ -11,14 +11,31 @@ ...@@ -11,14 +11,31 @@
11 <div class="pdf-viewer-container"> 11 <div class="pdf-viewer-container">
12 <!-- PDF内容区域 --> 12 <!-- PDF内容区域 -->
13 <div class="pdf-content" :class="{ 'pdf-no-select': preventSave }"> 13 <div class="pdf-content" :class="{ 'pdf-no-select': preventSave }">
14 - <PDF v-if="url && show && !loadingError" :src="url" :showProgress="true" :progressColor="'#1989fa'" 14 + <PDF v-if="url && show && !loadingError"
15 - :showPageTooltip="true" :showBackToTopBtn="true" :scrollThreshold="300" 15 + ref="pdfRef"
16 + :src="url"
17 + :showProgress="true"
18 + :progressColor="'#1989fa'"
19 + :showPageTooltip="true"
20 + :showBackToTopBtn="true"
21 + :scrollThreshold="300"
16 :pdfWidth="`${Math.round(100 * zoomLevel)}%`" 22 :pdfWidth="`${Math.round(100 * zoomLevel)}%`"
17 - :rowGap="8" :page="1" :cMapUrl="'https://unpkg.com/pdfjs-dist@3.7.107/cmaps/'" 23 + :rowGap="8"
18 - :withCredentials="false" :useSystemFonts="true" :stopAtErrors="false" :disableFontFace="false" 24 + :page="1"
19 - :disableRange="false" :disableStream="false" :disableAutoFetch="false" @onProgress="handleProgress" 25 + :cMapUrl="'https://unpkg.com/pdfjs-dist@3.7.107/cmaps/'"
20 - @onComplete="handleComplete" @onScroll="handleScroll" @onPageChange="handlePageChange" 26 + :withCredentials="false"
21 - @onPdfInit="handlePdfInit" @onError="handlePdfError" /> 27 + :useSystemFonts="true"
28 + :stopAtErrors="false"
29 + :disableFontFace="false"
30 + :disableRange="false"
31 + :disableStream="false"
32 + :disableAutoFetch="false"
33 + @onProgress="handleProgress"
34 + @onComplete="handleComplete"
35 + @onScroll="handleScroll"
36 + @onPageChange="handlePageChange"
37 + @onPdfInit="handlePdfInit"
38 + @onError="handlePdfError" />
22 39
23 <!-- 错误状态显示 --> 40 <!-- 错误状态显示 -->
24 <div v-if="loadingError" class="error-container"> 41 <div v-if="loadingError" class="error-container">
...@@ -34,7 +51,7 @@ ...@@ -34,7 +51,7 @@
34 </div> 51 </div>
35 52
36 <!-- 关闭按钮 --> 53 <!-- 关闭按钮 -->
37 - <van-button class="close-btn" type="default" icon="cross" round @click="emit('update:show', false)" /> 54 + <van-button class="close-btn" type="default" icon="cross" round @click="handleClose" />
38 55
39 <!-- 缩放控制按钮 --> 56 <!-- 缩放控制按钮 -->
40 <div v-if="!loading && !loadingError" class="zoom-controls"> 57 <div v-if="!loading && !loadingError" class="zoom-controls">
...@@ -70,7 +87,7 @@ ...@@ -70,7 +87,7 @@
70 </template> 87 </template>
71 88
72 <script setup> 89 <script setup>
73 -import { ref, watch, nextTick } from 'vue'; 90 +import { ref, watch, nextTick, onUnmounted } from 'vue';
74 import PDF from "pdf-vue3"; 91 import PDF from "pdf-vue3";
75 92
76 /** 93 /**
...@@ -102,7 +119,7 @@ const props = defineProps({ ...@@ -102,7 +119,7 @@ const props = defineProps({
102 /** 119 /**
103 * 事件定义 120 * 事件定义
104 */ 121 */
105 -const emit = defineEmits(['update:show', 'onLoad', 'onProgress', 'onComplete']); 122 +const emit = defineEmits(['update:show', 'onLoad', 'onProgress', 'onComplete', 'onClose', 'onDestroy']);
106 123
107 // 响应式数据 124 // 响应式数据
108 const loading = ref(true); 125 const loading = ref(true);
...@@ -111,6 +128,7 @@ const loadingError = ref(false); ...@@ -111,6 +128,7 @@ const loadingError = ref(false);
111 const errorMessage = ref(''); 128 const errorMessage = ref('');
112 const zoomLevel = ref(1); // 缩放级别,1为100% 129 const zoomLevel = ref(1); // 缩放级别,1为100%
113 const scrollPosition = ref({ x: 0, y: 0 }); // 记录滚动位置 130 const scrollPosition = ref({ x: 0, y: 0 }); // 记录滚动位置
131 +const pdfRef = ref(null); // PDF组件引用
114 132
115 // 超时处理相关 133 // 超时处理相关
116 const loadingTimeout = ref(30000); // 超时时间,默认30秒 134 const loadingTimeout = ref(30000); // 超时时间,默认30秒
...@@ -131,13 +149,21 @@ watch(() => props.show, (newVal) => { ...@@ -131,13 +149,21 @@ watch(() => props.show, (newVal) => {
131 errorMessage.value = ''; 149 errorMessage.value = '';
132 zoomLevel.value = 1; // 重置缩放级别 150 zoomLevel.value = 1; // 重置缩放级别
133 } else if (!newVal) { 151 } else if (!newVal) {
134 - // 弹窗关闭时重置状态 152 + // 弹窗关闭时重置状态并清理资源
135 clearAllTimers(); // 清除计时器 153 clearAllTimers(); // 清除计时器
136 - loading.value = true; 154 +
137 - loadingError.value = false; 155 + // 延迟清理,确保PDF组件有时间完成内部清理
138 - loadingProgress.value = 0; 156 + setTimeout(() => {
139 - errorMessage.value = ''; 157 + loading.value = false;
140 - zoomLevel.value = 1; // 重置缩放级别 158 + loadingError.value = false;
159 + loadingProgress.value = 0;
160 + errorMessage.value = '';
161 + zoomLevel.value = 1; // 重置缩放级别
162 + scrollPosition.value = { x: 0, y: 0 }; // 重置滚动位置
163 +
164 + // 触发关闭销毁事件,通知父组件清理引用
165 + emit('onClose');
166 + }, 100); // 100ms延迟,给PDF组件时间清理
141 } 167 }
142 }); 168 });
143 169
...@@ -302,6 +328,28 @@ const retryLoad = () => { ...@@ -302,6 +328,28 @@ const retryLoad = () => {
302 }; 328 };
303 329
304 /** 330 /**
331 + * 处理关闭弹窗
332 + */
333 +const handleClose = () => {
334 + // 先清理所有计时器
335 + clearAllTimers();
336 +
337 + // 如果PDF组件存在,尝试清理其内部状态
338 + if (pdfRef.value && typeof pdfRef.value.destroy === 'function') {
339 + try {
340 + pdfRef.value.destroy();
341 + } catch (error) {
342 + console.warn('PDF组件销毁时出现警告:', error);
343 + }
344 + }
345 +
346 + // 使用nextTick确保在DOM更新前完成清理
347 + nextTick(() => {
348 + emit('update:show', false);
349 + });
350 +};
351 +
352 +/**
305 * 放大PDF 353 * 放大PDF
306 */ 354 */
307 const zoomIn = () => { 355 const zoomIn = () => {
......