hookehuyr

feat(图片预览): 添加自定义关闭按钮并调整预览样式

在图片预览组件中添加自定义关闭按钮,移除默认关闭功能,并调整相关样式以提升用户体验。同时优化PDF查看器的控制栏样式和交互效果。
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 14:11:50 4 + * @LastEditTime: 2025-10-22 15:08:11
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 -->
...@@ -53,8 +53,8 @@ ...@@ -53,8 +53,8 @@
53 <!-- 已移除顶部关闭按钮,关闭功能迁移至控制栏 --> 53 <!-- 已移除顶部关闭按钮,关闭功能迁移至控制栏 -->
54 54
55 <!-- 缩放控制按钮 --> 55 <!-- 缩放控制按钮 -->
56 - <div 56 + <div
57 - v-if="!loading && !loadingError" 57 + v-if="!loading && !loadingError"
58 class="zoom-controls" 58 class="zoom-controls"
59 :class="{ 'dragging': isDragging }" 59 :class="{ 'dragging': isDragging }"
60 :style="{ bottom: controlsY + 'px' }" 60 :style="{ bottom: controlsY + 'px' }"
...@@ -206,7 +206,7 @@ const handleDragStart = (e) => { ...@@ -206,7 +206,7 @@ const handleDragStart = (e) => {
206 if (e.target.closest('.zoom-btn') || e.target.closest('.page-jump')) { 206 if (e.target.closest('.zoom-btn') || e.target.closest('.page-jump')) {
207 return; 207 return;
208 } 208 }
209 - 209 +
210 dragStartY.value = e.clientY; 210 dragStartY.value = e.clientY;
211 initialControlsY.value = controlsY.value; // 记录拖动开始时的位置 211 initialControlsY.value = controlsY.value; // 记录拖动开始时的位置
212 dragOffset.value = 0; 212 dragOffset.value = 0;
...@@ -220,19 +220,19 @@ const handleDragStart = (e) => { ...@@ -220,19 +220,19 @@ const handleDragStart = (e) => {
220 */ 220 */
221 const handleDragMove = (e) => { 221 const handleDragMove = (e) => {
222 const deltaY = Math.abs(dragStartY.value - e.clientY); 222 const deltaY = Math.abs(dragStartY.value - e.clientY);
223 - 223 +
224 // 只有移动距离超过阈值才开始拖动 224 // 只有移动距离超过阈值才开始拖动
225 if (!isDragging.value && deltaY > dragThreshold) { 225 if (!isDragging.value && deltaY > dragThreshold) {
226 isDragging.value = true; 226 isDragging.value = true;
227 e.preventDefault(); 227 e.preventDefault();
228 } 228 }
229 - 229 +
230 if (!isDragging.value) return; 230 if (!isDragging.value) return;
231 - 231 +
232 const actualDeltaY = dragStartY.value - e.clientY; // 向上为正,向下为负 232 const actualDeltaY = dragStartY.value - e.clientY; // 向上为正,向下为负
233 const dampingFactor = 0.3; // 阻尼系数,降低移动速度 233 const dampingFactor = 0.3; // 阻尼系数,降低移动速度
234 const dampedDelta = actualDeltaY * dampingFactor; 234 const dampedDelta = actualDeltaY * dampingFactor;
235 - 235 +
236 const newY = Math.max(20, Math.min(window.innerHeight - 100, initialControlsY.value + dampedDelta)); 236 const newY = Math.max(20, Math.min(window.innerHeight - 100, initialControlsY.value + dampedDelta));
237 controlsY.value = newY; 237 controlsY.value = newY;
238 dragOffset.value = dampedDelta; 238 dragOffset.value = dampedDelta;
...@@ -259,7 +259,7 @@ const handleTouchStart = (e) => { ...@@ -259,7 +259,7 @@ const handleTouchStart = (e) => {
259 if (e.target.closest('.zoom-btn') || e.target.closest('.page-jump')) { 259 if (e.target.closest('.zoom-btn') || e.target.closest('.page-jump')) {
260 return; 260 return;
261 } 261 }
262 - 262 +
263 dragStartY.value = e.touches[0].clientY; 263 dragStartY.value = e.touches[0].clientY;
264 initialControlsY.value = controlsY.value; // 记录拖动开始时的位置 264 initialControlsY.value = controlsY.value; // 记录拖动开始时的位置
265 dragOffset.value = 0; 265 dragOffset.value = 0;
...@@ -272,21 +272,21 @@ const handleTouchStart = (e) => { ...@@ -272,21 +272,21 @@ const handleTouchStart = (e) => {
272 */ 272 */
273 const handleTouchMove = (e) => { 273 const handleTouchMove = (e) => {
274 if (e.touches.length !== 1) return; 274 if (e.touches.length !== 1) return;
275 - 275 +
276 const deltaY = Math.abs(dragStartY.value - e.touches[0].clientY); 276 const deltaY = Math.abs(dragStartY.value - e.touches[0].clientY);
277 - 277 +
278 // 只有移动距离超过阈值才开始拖动 278 // 只有移动距离超过阈值才开始拖动
279 if (!isDragging.value && deltaY > dragThreshold) { 279 if (!isDragging.value && deltaY > dragThreshold) {
280 isDragging.value = true; 280 isDragging.value = true;
281 e.preventDefault(); 281 e.preventDefault();
282 } 282 }
283 - 283 +
284 if (!isDragging.value) return; 284 if (!isDragging.value) return;
285 - 285 +
286 const actualDeltaY = dragStartY.value - e.touches[0].clientY; // 向上为正,向下为负 286 const actualDeltaY = dragStartY.value - e.touches[0].clientY; // 向上为正,向下为负
287 const dampingFactor = 0.4; // 移动端稍微高一点的阻尼系数 287 const dampingFactor = 0.4; // 移动端稍微高一点的阻尼系数
288 const dampedDelta = actualDeltaY * dampingFactor; 288 const dampedDelta = actualDeltaY * dampingFactor;
289 - 289 +
290 const newY = Math.max(20, Math.min(window.innerHeight - 100, initialControlsY.value + dampedDelta)); 290 const newY = Math.max(20, Math.min(window.innerHeight - 100, initialControlsY.value + dampedDelta));
291 controlsY.value = newY; 291 controlsY.value = newY;
292 dragOffset.value = dampedDelta; 292 dragOffset.value = dampedDelta;
...@@ -864,27 +864,30 @@ const applyPinchZoom = (newZoom, centerX, centerY, container) => { ...@@ -864,27 +864,30 @@ const applyPinchZoom = (newZoom, centerX, centerY, container) => {
864 flex-direction: row; 864 flex-direction: row;
865 align-items: center; 865 align-items: center;
866 gap: 12px; 866 gap: 12px;
867 - background: rgba(255, 255, 255, 0.95); 867 + background: rgba(255, 255, 255, 0.15);
868 padding: 12px 20px; 868 padding: 12px 20px;
869 border-radius: 25px; 869 border-radius: 25px;
870 box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); 870 box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
871 - backdrop-filter: blur(8px); 871 + backdrop-filter: blur(1px);
872 + border: 1px solid rgba(255, 255, 255, 0.3);
872 transition: all 0.3s ease; 873 transition: all 0.3s ease;
873 cursor: grab; 874 cursor: grab;
874 user-select: none; 875 user-select: none;
875 } 876 }
876 877
877 .zoom-controls:hover { 878 .zoom-controls:hover {
878 - background: rgba(255, 255, 255, 1); 879 + background: rgba(255, 255, 255, 0.7);
879 box-shadow: 0 6px 30px rgba(0, 0, 0, 0.2); 880 box-shadow: 0 6px 30px rgba(0, 0, 0, 0.2);
880 transform: translateX(-50%) translateY(-2px); 881 transform: translateX(-50%) translateY(-2px);
882 + backdrop-filter: blur(20px);
881 } 883 }
882 884
883 .zoom-controls.dragging { 885 .zoom-controls.dragging {
884 cursor: grabbing; 886 cursor: grabbing;
885 transform: translateX(-50%) scale(1.05); 887 transform: translateX(-50%) scale(1.05);
886 box-shadow: 0 8px 40px rgba(0, 0, 0, 0.25); 888 box-shadow: 0 8px 40px rgba(0, 0, 0, 0.25);
887 - background: rgba(255, 255, 255, 1); 889 + background: rgba(255, 255, 255, 0.8);
890 + backdrop-filter: blur(25px);
888 transition: none; 891 transition: none;
889 } 892 }
890 893
......
...@@ -221,13 +221,18 @@ ...@@ -221,13 +221,18 @@
221 <van-image-preview 221 <van-image-preview
222 v-model:show="showPreview" 222 v-model:show="showPreview"
223 :images="previewImages" 223 :images="previewImages"
224 - :close-on-click-image="true" 224 + :show-index="false"
225 - :show-index="true" 225 + :close-on-click-image="false"
226 - closeable
227 > 226 >
228 <template #image="{ src, style, onLoad }"> 227 <template #image="{ src, style, onLoad }">
229 <img :src="src" :style="[{ width: '100%' }, style]" @load="onLoad" /> 228 <img :src="src" :style="[{ width: '100%' }, style]" @load="onLoad" />
230 </template> 229 </template>
230 + <template #cover>
231 + <!-- 关闭按钮 -->
232 + <div class="image-preview-close-btn" @click="closeImagePreview">
233 + <van-icon name="cross" size="20" color="#fff" />
234 + </div>
235 + </template>
231 </van-image-preview> 236 </van-image-preview>
232 237
233 <!-- 课程目录弹出层 --> 238 <!-- 课程目录弹出层 -->
...@@ -753,6 +758,11 @@ const showImagePreview = (startPosition) => { ...@@ -753,6 +758,11 @@ const showImagePreview = (startPosition) => {
753 showPreview.value = true; 758 showPreview.value = true;
754 }; 759 };
755 760
761 +// 关闭图片预览
762 +const closeImagePreview = () => {
763 + showPreview.value = false;
764 +};
765 +
756 // 评论列表分页参数 766 // 评论列表分页参数
757 const popupCommentList = ref([]); 767 const popupCommentList = ref([]);
758 const popupLoading = ref(false); 768 const popupLoading = ref(false);
...@@ -1967,4 +1977,33 @@ const getFileType = (fileName) => { ...@@ -1967,4 +1977,33 @@ const getFileType = (fileName) => {
1967 width: 100%; 1977 width: 100%;
1968 padding: 0px; 1978 padding: 0px;
1969 } 1979 }
1980 +
1981 +// 图片预览关闭按钮样式
1982 +.image-preview-close-btn {
1983 + position: fixed;
1984 + bottom: 30px;
1985 + left: 50%;
1986 + transform: translateX(-50%);
1987 + z-index: 1000;
1988 + width: 50px;
1989 + height: 50px;
1990 + background: rgba(0, 0, 0, 0.6);
1991 + border-radius: 50%;
1992 + display: flex;
1993 + align-items: center;
1994 + justify-content: center;
1995 + cursor: pointer;
1996 + transition: all 0.3s ease;
1997 + backdrop-filter: blur(10px);
1998 + border: 1px solid rgba(255, 255, 255, 0.2);
1999 +}
2000 +
2001 +.image-preview-close-btn:hover {
2002 + background: rgba(0, 0, 0, 0.8);
2003 + transform: translateX(-50%) scale(1.1);
2004 +}
2005 +
2006 +.image-preview-close-btn:active {
2007 + transform: translateX(-50%) scale(0.95);
2008 +}
1970 </style> 2009 </style>
......