123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- <template>
- <div class="yaxq-bottom-jcxx yawd">
- <div class="page-tool">
- <div class="page-tool-item" @click="zoomOut">缩小</div>
- <div class="page-tool-item" @click="lastPage">上一页</div>
- <div class="page-tool-item">{{ state.pageNum }}/{{ state.numPages }}</div>
- <div class="page-tool-item" @click="nextPage">下一页</div>
- <div class="page-tool-item" @click="zoomIn">放大</div>
- </div>
- <div class="pdf-preview"
- v-loading="pdfLoading"
- @mousedown="startDrag"
- @mousemove="doDrag"
- @mouseup="endDrag"
- @mouseleave="endDrag">
- <div class="pdf-container" :style="containerStyle">
- <vue-pdf-embed
- v-if="show"
- :source="state.source"
- class="vue-pdf-embed"
- :style="{ transform: `scale(${state.scale})` }"
- :page="state.pageNum"
- @loaded="handleDocument" />
- </div>
- </div>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, reactive, computed, onMounted } from 'vue';
- import VuePdfEmbed from "vue-pdf-embed";
- const props = defineProps({
- url: String
- });
- // PDF状态
- const state = reactive({
- source: '' as string | undefined,
- pageNum: 1,
- scale: 1,
- numPages: 0,
- });
- // 拖拽状态
- const dragState = reactive({
- isDragging: false,
- startX: 0,
- startY: 0,
- translateX: 0,
- translateY: 0,
- lastTranslateX: 0,
- lastTranslateY: 0
- });
- // 加载状态
- const pdfLoading = ref(false);
- const show = ref(false);
- // 容器样式计算
- const containerStyle = computed(() => ({
- transform: `translate(${dragState.translateX}px, ${dragState.translateY}px)`,
- cursor: dragState.isDragging ? 'grabbing' : 'grab'
- }));
- // 拖拽处理
- const startDrag = (e: MouseEvent) => {
- dragState.isDragging = true;
- dragState.startX = e.clientX - dragState.translateX;
- dragState.startY = e.clientY - dragState.translateY;
- };
- const doDrag = (e: MouseEvent) => {
- if (!dragState.isDragging) return;
- dragState.translateX = e.clientX - dragState.startX;
- dragState.translateY = e.clientY - dragState.startY;
- };
- const endDrag = () => {
- if (!dragState.isDragging) return;
- dragState.isDragging = false;
- dragState.lastTranslateX = dragState.translateX;
- dragState.lastTranslateY = dragState.translateY;
- };
- // 缩放功能
- const zoomOut = () => {
- state.scale = Math.max(0.5, state.scale - 0.1);
- resetPosition();
- };
- const zoomIn = () => {
- state.scale = Math.min(3, state.scale + 0.1);
- resetPosition();
- };
- // 重置位置
- const resetPosition = () => {
- dragState.translateX = 0;
- dragState.translateY = 0;
- dragState.lastTranslateX = 0;
- dragState.lastTranslateY = 0;
- };
- // 翻页功能
- const lastPage = () => {
- if (state.pageNum > 1) {
- state.pageNum -= 1;
- resetPosition();
- }
- };
- const nextPage = () => {
- if (state.pageNum < state.numPages) {
- state.pageNum += 1;
- resetPosition();
- }
- };
- // PDF加载完成
- const handleDocument = (pdf: any) => {
- if (pdf.numPages) {
- pdfLoading.value = false;
- state.numPages = pdf.numPages;
- }
- };
- // 初始化
- onMounted(() => {
- if (props.url) {
- state.source = props.url;
- pdfLoading.value = true;
- show.value = true;
- }
- });
- </script>
- <style scoped lang="scss">
- .yawd {
- display: flex;
- justify-content: center;
- position: relative;
- //height: 100%;
- .page-tool {
- position: fixed;
- bottom: 20px;
- left: 50%;
- transform: translateX(-50%);
- padding: 5px 15px;
- display: flex;
- align-items: center;
- background: #424242;
- color: white;
- border-radius: 5px;
- z-index: 999;
- cursor: pointer;
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
- &-item {
- font-size: 14px;
- padding: 5px 15px;
- transition: background 0.3s;
- border-radius: 3px;
- &:hover {
- background: rgba(255, 255, 255, 0.1);
- }
- &:not(:last-child) {
- border-right: 1px solid rgba(255, 255, 255, 0.2);
- }
- }
- }
- .pdf-preview {
- width: 100%;
- height: calc(100% - 60px);
- overflow: hidden;
- position: relative;
- background: #f0f0f0;
- //.pdf-container {
- // transition: transform 0.3s ease;
- // will-change: transform;
- // padding: 20px;
- //}
- .vue-pdf-embed {
- transform-origin: 0 0;
- user-select: none;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
- background: white !important;
- }
- }
- }
- </style>
|