hookehuyr

feat(PdfViewer): 添加放大缩小图标并优化缩放功能

将PDF查看器的缩放按钮从Vant组件替换为FontAwesome图标
添加faMagnifyingGlassPlus和faMagnifyingGlassMinus图标
优化双指缩放的手势处理逻辑
1 <!-- 1 <!--
2 * @Date: 2025-01-21 2 * @Date: 2025-01-21
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2025-10-22 12:17:03 4 + * @LastEditTime: 2025-10-22 13:28:38
5 * @FilePath: /mlaj/src/components/ui/PdfViewer.vue 5 * @FilePath: /mlaj/src/components/ui/PdfViewer.vue
6 * @Description: PDF预览组件 - 使用pdf-vue3库 6 * @Description: PDF预览组件 - 使用pdf-vue3库
7 --> 7 -->
...@@ -55,7 +55,8 @@ ...@@ -55,7 +55,8 @@
55 <!-- 缩放控制按钮 --> 55 <!-- 缩放控制按钮 -->
56 <div v-if="!loading && !loadingError" class="zoom-controls"> 56 <div v-if="!loading && !loadingError" class="zoom-controls">
57 <van-button class="zoom-btn zoom-close-btn" type="default" icon="cross" round @click="handleClose" /> 57 <van-button class="zoom-btn zoom-close-btn" type="default" icon="cross" round @click="handleClose" />
58 - <van-button class="zoom-btn zoom-in-btn" type="default" icon="plus" round @click="zoomIn" /> 58 + <!-- <van-button class="zoom-btn zoom-in-btn" type="default" icon="plus" round @click="zoomIn" /> -->
59 + <font-awesome-icon icon="magnifying-glass-plus" class="text-2xl text-gray-600 ml-2 mr-2" @click="zoomIn" />
59 <div class="page-jump" @click="focusPageInput"> 60 <div class="page-jump" @click="focusPageInput">
60 <span class="page-display">{{ currentPage }}/{{ totalPages || 0 }}</span> 61 <span class="page-display">{{ currentPage }}/{{ totalPages || 0 }}</span>
61 <input 62 <input
...@@ -70,7 +71,8 @@ ...@@ -70,7 +71,8 @@
70 v-show="isEditingPage" 71 v-show="isEditingPage"
71 /> 72 />
72 </div> 73 </div>
73 - <van-button class="zoom-btn zoom-out-btn" type="default" icon="minus" round @click="zoomOut" /> 74 + <!-- <van-button class="zoom-btn zoom-out-btn" type="default" icon="minus" round @click="zoomOut" /> -->
75 + <font-awesome-icon icon="magnifying-glass-minus" class="text-2xl text-gray-600 ml-2 mr-2" @click="zoomOut" />
74 <van-button class="zoom-btn zoom-reset-btn" type="default" round @click="resetZoom"> 76 <van-button class="zoom-btn zoom-reset-btn" type="default" round @click="resetZoom">
75 <van-icon name="replay" size="16" /> 77 <van-icon name="replay" size="16" />
76 </van-button> 78 </van-button>
...@@ -570,7 +572,7 @@ const addPinchZoomListeners = (container) => { ...@@ -570,7 +572,7 @@ const addPinchZoomListeners = (container) => {
570 // 触摸开始 572 // 触摸开始
571 container.addEventListener('touchstart', (e) => { 573 container.addEventListener('touchstart', (e) => {
572 touches = Array.from(e.touches); 574 touches = Array.from(e.touches);
573 - 575 +
574 if (touches.length === 2) { 576 if (touches.length === 2) {
575 // 双指触摸开始 577 // 双指触摸开始
576 e.preventDefault(); 578 e.preventDefault();
...@@ -587,21 +589,21 @@ const addPinchZoomListeners = (container) => { ...@@ -587,21 +589,21 @@ const addPinchZoomListeners = (container) => {
587 container.addEventListener('touchmove', (e) => { 589 container.addEventListener('touchmove', (e) => {
588 if (e.touches.length === 2 && isZooming) { 590 if (e.touches.length === 2 && isZooming) {
589 e.preventDefault(); 591 e.preventDefault();
590 - 592 +
591 const currentTouches = Array.from(e.touches); 593 const currentTouches = Array.from(e.touches);
592 const currentDistance = getDistance(currentTouches[0], currentTouches[1]); 594 const currentDistance = getDistance(currentTouches[0], currentTouches[1]);
593 const scale = currentDistance / initialDistance; 595 const scale = currentDistance / initialDistance;
594 - 596 +
595 // 计算新的缩放级别 597 // 计算新的缩放级别
596 let newZoom = initialZoom * scale; 598 let newZoom = initialZoom * scale;
597 newZoom = Math.max(0.5, Math.min(3, newZoom)); // 限制缩放范围 599 newZoom = Math.max(0.5, Math.min(3, newZoom)); // 限制缩放范围
598 - 600 +
599 // 获取缩放中心点 601 // 获取缩放中心点
600 const center = getCenter(currentTouches[0], currentTouches[1]); 602 const center = getCenter(currentTouches[0], currentTouches[1]);
601 const rect = container.getBoundingClientRect(); 603 const rect = container.getBoundingClientRect();
602 const centerX = center.x - rect.left; 604 const centerX = center.x - rect.left;
603 const centerY = center.y - rect.top; 605 const centerY = center.y - rect.top;
604 - 606 +
605 // 应用缩放 607 // 应用缩放
606 applyPinchZoom(newZoom, centerX, centerY, container); 608 applyPinchZoom(newZoom, centerX, centerY, container);
607 } 609 }
...@@ -631,18 +633,18 @@ const applyPinchZoom = (newZoom, centerX, centerY, container) => { ...@@ -631,18 +633,18 @@ const applyPinchZoom = (newZoom, centerX, centerY, container) => {
631 const oldZoom = zoomLevel.value; 633 const oldZoom = zoomLevel.value;
632 const oldScrollLeft = container.scrollLeft; 634 const oldScrollLeft = container.scrollLeft;
633 const oldScrollTop = container.scrollTop; 635 const oldScrollTop = container.scrollTop;
634 - 636 +
635 // 更新缩放级别 637 // 更新缩放级别
636 zoomLevel.value = newZoom; 638 zoomLevel.value = newZoom;
637 - 639 +
638 // 等待DOM更新后调整滚动位置 640 // 等待DOM更新后调整滚动位置
639 nextTick(() => { 641 nextTick(() => {
640 const zoomRatio = newZoom / oldZoom; 642 const zoomRatio = newZoom / oldZoom;
641 - 643 +
642 // 计算新的滚动位置,以缩放中心为锚点 644 // 计算新的滚动位置,以缩放中心为锚点
643 const newScrollLeft = (oldScrollLeft + centerX) * zoomRatio - centerX; 645 const newScrollLeft = (oldScrollLeft + centerX) * zoomRatio - centerX;
644 const newScrollTop = (oldScrollTop + centerY) * zoomRatio - centerY; 646 const newScrollTop = (oldScrollTop + centerY) * zoomRatio - centerY;
645 - 647 +
646 // 应用新的滚动位置 648 // 应用新的滚动位置
647 container.scrollLeft = Math.max(0, newScrollLeft); 649 container.scrollLeft = Math.max(0, newScrollLeft);
648 container.scrollTop = Math.max(0, newScrollTop); 650 container.scrollTop = Math.max(0, newScrollTop);
......
...@@ -18,10 +18,10 @@ import { library } from '@fortawesome/fontawesome-svg-core' ...@@ -18,10 +18,10 @@ import { library } from '@fortawesome/fontawesome-svg-core'
18 /* import font awesome icon component */ 18 /* import font awesome icon component */
19 import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' 19 import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
20 /* import specific icons */ 20 /* import specific icons */
21 -import { faCirclePause, faCirclePlay, faPlay, faPause, faBackwardStep, faForwardStep, faVolumeUp, faRedo, faRepeat, faList, faChevronDown, faVolumeOff, faXmark, faFileAlt, faTimes, faEye, faFilePdf, faExternalLinkAlt, faSpinner, faExclamationCircle, faDownload, faVenus, faMars } from '@fortawesome/free-solid-svg-icons' 21 +import { faCirclePause, faCirclePlay, faPlay, faPause, faBackwardStep, faForwardStep, faVolumeUp, faRedo, faRepeat, faList, faChevronDown, faVolumeOff, faXmark, faFileAlt, faTimes, faEye, faFilePdf, faExternalLinkAlt, faSpinner, faExclamationCircle, faDownload, faVenus, faMars, faMagnifyingGlassPlus, faMagnifyingGlassMinus } from '@fortawesome/free-solid-svg-icons'
22 22
23 /* add icons to the library */ 23 /* add icons to the library */
24 -library.add(faCirclePause, faCirclePlay, faPlay, faPause, faBackwardStep, faForwardStep, faVolumeUp, faRedo, faRepeat, faList, faChevronDown, faVolumeOff, faXmark, faFileAlt, faTimes, faEye, faFilePdf, faExternalLinkAlt, faSpinner, faExclamationCircle, faDownload, faVenus, faMars ) 24 +library.add(faCirclePause, faCirclePlay, faPlay, faPause, faBackwardStep, faForwardStep, faVolumeUp, faRedo, faRepeat, faList, faChevronDown, faVolumeOff, faXmark, faFileAlt, faTimes, faEye, faFilePdf, faExternalLinkAlt, faSpinner, faExclamationCircle, faDownload, faVenus, faMars, faMagnifyingGlassPlus, faMagnifyingGlassMinus )
25 25
26 if (!Array.prototype.at) { 26 if (!Array.prototype.at) {
27 Array.prototype.at = function(n) { 27 Array.prototype.at = function(n) {
......