PdfPreviewPage.vue
3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<!--
* @Date: 2024-01-17
* @Description: PDF预览页面
-->
<template>
<div class="pdf-preview-page bg-white min-h-screen flex flex-col">
<!-- 顶部导航栏 -->
<div class="flex items-center justify-between p-4 bg-white border-b sticky top-0 z-10">
<div class="flex items-center space-x-2">
<font-awesome-icon icon="file-pdf" class="text-red-500 text-xl" />
<span class="text-gray-900 font-medium">{{ title }}</span>
</div>
<div class="flex items-center space-x-4">
<a :href="pdfUrl" target="_blank" class="text-blue-600 hover:text-blue-800">
<font-awesome-icon icon="external-link-alt" class="mr-1" />
新窗口打开
</a>
<button @click="goBack" class="text-gray-500 hover:text-gray-700">
<font-awesome-icon icon="times" />
</button>
</div>
</div>
<!-- PDF内容区域 -->
<div class="flex-1 overflow-y-auto bg-gray-100 p-4">
<div v-for="pageNum in pageNums" :key="pageNum" class="mb-4" ref="pageRefs">
<VuePdfEmbed
v-if="pageVisibility[pageNum]"
:source="{ url: pdfUrl }"
:page="pageNum"
:scale="1.5"
:render-text="true"
style="width: 100%;"
/>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, onMounted, onBeforeUnmount, nextTick } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import VuePdfEmbed, { useVuePdfEmbed } from 'vue-pdf-embed';
const route = useRoute();
const router = useRouter();
// 获取路由参数
const title = ref(route.query.title || 'PDF预览');
const pdfUrl = ref(route.query.url || '');
// PDF页面相关
const pageRefs = ref([]);
const pageVisibility = ref({});
let pageIntersectionObserver;
// 使用PDF嵌入组件
const { doc } = useVuePdfEmbed({
source: { url: pdfUrl.value },
});
// 计算总页数
const pageNums = computed(() =>
doc.value
? [...Array(doc.value.numPages + 1).keys()].slice(1)
: []
);
// 重置页面交叉观察器
const resetPageIntersectionObserver = () => {
pageIntersectionObserver?.disconnect();
pageIntersectionObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const index = pageRefs.value.indexOf(entry.target);
const pageNum = pageNums.value[index];
pageVisibility.value[pageNum] = true;
}
});
});
pageRefs.value.forEach((element) => {
if (element) {
pageIntersectionObserver.observe(element);
}
});
};
// 返回上一页
const goBack = () => {
router.back();
};
// 监听页数变化
watch(pageNums, (newPageNums) => {
if (newPageNums.length > 0) {
pageVisibility.value = { [newPageNums[0]]: true };
nextTick(resetPageIntersectionObserver);
}
});
// 组件卸载前清理
onBeforeUnmount(() => {
pageIntersectionObserver?.disconnect();
});
</script>
<style lang="less" scoped>
.pdf-preview-page {
.pdf-content {
background-color: #f3f4f6;
}
}
</style>