Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Hooke
/
mlaj
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
hookehuyr
2025-10-21 15:21:08 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
0b41d695521ac29cb192975863d1991c1cf9ce5d
0b41d695
1 parent
adbdf240
feat(PdfViewer): 添加PDF缩放功能和控制按钮
添加缩放功能,支持放大、缩小和重置操作 更新PDF显示宽度以匹配缩放级别 添加缩放控制按钮的样式和交互逻辑
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
105 additions
and
4 deletions
src/components.d.ts
src/components/ui/PdfViewer.vue
src/components.d.ts
View file @
0b41d69
...
...
@@ -18,7 +18,6 @@ declare module 'vue' {
CourseCard
:
typeof
import
(
'./components/ui/CourseCard.vue'
)[
'default'
]
CourseImageCard
:
typeof
import
(
'./components/ui/CourseImageCard.vue'
)[
'default'
]
CourseList
:
typeof
import
(
'./components/courses/CourseList.vue'
)[
'default'
]
FilePreviewPopup
:
typeof
import
(
'./components/ui/FilePreviewPopup.vue'
)[
'default'
]
FormPage
:
typeof
import
(
'./components/infoEntry/formPage.vue'
)[
'default'
]
FrostedGlass
:
typeof
import
(
'./components/ui/FrostedGlass.vue'
)[
'default'
]
GradientHeader
:
typeof
import
(
'./components/ui/GradientHeader.vue'
)[
'default'
]
...
...
src/components/ui/PdfViewer.vue
View file @
0b41d69
<!--
* @Date: 2025-01-21
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-10-21 1
4:33:07
* @LastEditTime: 2025-10-21 1
5:20:39
* @FilePath: /mlaj/src/components/ui/PdfViewer.vue
* @Description: PDF预览组件 - 使用pdf-vue3库
-->
...
...
@@ -12,7 +12,8 @@
<!-- PDF内容区域 -->
<div class="pdf-content" :class="{ 'pdf-no-select': preventSave }">
<PDF v-if="url && show && !loadingError" :src="url" :showProgress="true" :progressColor="'#1989fa'"
:showPageTooltip="true" :showBackToTopBtn="true" :scrollThreshold="300" :pdfWidth="'100%'"
:showPageTooltip="true" :showBackToTopBtn="true" :scrollThreshold="300"
:pdfWidth="`${Math.round(100 * zoomLevel)}%`"
:rowGap="8" :page="1" :cMapUrl="'https://unpkg.com/pdfjs-dist@3.7.107/cmaps/'"
:withCredentials="false" :useSystemFonts="true" :stopAtErrors="false" :disableFontFace="false"
:disableRange="false" :disableStream="false" :disableAutoFetch="false" @onProgress="handleProgress"
...
...
@@ -35,6 +36,16 @@
<!-- 关闭按钮 -->
<van-button class="close-btn" type="default" icon="cross" round @click="emit('update:show', false)" />
<!-- 缩放控制按钮 -->
<div v-if="!loading && !loadingError" class="zoom-controls">
<van-button class="zoom-btn zoom-out-btn" type="default" icon="minus" round @click="zoomOut" />
<div class="zoom-level">{{ Math.round(zoomLevel * 100) }}%</div>
<van-button class="zoom-btn zoom-in-btn" type="default" icon="plus" round @click="zoomIn" />
<van-button class="zoom-btn zoom-reset-btn" type="default" round @click="resetZoom">
<van-icon name="replay" size="16" />
</van-button>
</div>
<!-- 加载遮罩 -->
<van-overlay :show="loading && !loadingError">
<div class="wrapper" @click.stop>
...
...
@@ -46,7 +57,7 @@
<!-- 加载文字 -->
<div class="loading-text">
<div class="loading-title">
正在加载PDF文档
</div>
<div class="loading-title">
{{ title }}
</div>
<div class="loading-subtitle">
{{ loadingProgress < 10 ? '正在连接服务器...' : loadingProgress < 50 ? '正在下载文件...' :
loadingProgress < 90 ? '正在解析文档...' : '即将完成...' }} </div>
...
...
@@ -98,6 +109,7 @@ const loading = ref(true);
const loadingProgress = ref(0);
const loadingError = ref(false);
const errorMessage = ref('');
const zoomLevel = ref(1); // 缩放级别,1为100%
/**
* 监听show属性变化,控制PDF加载
...
...
@@ -109,12 +121,14 @@ watch(() => props.show, (newVal) => {
loadingError.value = false;
loadingProgress.value = 0;
errorMessage.value = '';
zoomLevel.value = 1; // 重置缩放级别
} else if (!newVal) {
// 弹窗关闭时重置状态
loading.value = true;
loadingError.value = false;
loadingProgress.value = 0;
errorMessage.value = '';
zoomLevel.value = 1; // 重置缩放级别
}
});
...
...
@@ -128,6 +142,7 @@ watch(() => props.url, (newUrl) => {
loadingError.value = false;
loadingProgress.value = 0;
errorMessage.value = '';
zoomLevel.value = 1; // 重置缩放级别
}
});
...
...
@@ -214,6 +229,32 @@ const retryLoad = () => {
loading.value = true;
loadingProgress.value = 0;
errorMessage.value = '';
zoomLevel.value = 1; // 重置缩放级别
};
/**
* 放大PDF
*/
const zoomIn = () => {
if (zoomLevel.value < 3) { // 最大放大到300%
zoomLevel.value = Math.min(3, zoomLevel.value + 0.25);
}
};
/**
* 缩小PDF
*/
const zoomOut = () => {
if (zoomLevel.value > 0.5) { // 最小缩小到50%
zoomLevel.value = Math.max(0.5, zoomLevel.value - 0.25);
}
};
/**
* 重置缩放
*/
const resetZoom = () => {
zoomLevel.value = 1;
};
/**
...
...
@@ -335,6 +376,67 @@ const addPreventSaveListeners = () => {
color: #fff;
}
/* 缩放控制按钮样式 */
.zoom-controls {
position: fixed;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
z-index: 100;
display: flex;
flex-direction: row;
align-items: center;
gap: 12px;
background: rgba(255, 255, 255, 0.95);
padding: 12px 20px;
border-radius: 25px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
backdrop-filter: blur(8px);
transition: all 0.3s ease;
}
.zoom-controls:hover {
background: rgba(255, 255, 255, 1);
box-shadow: 0 6px 30px rgba(0, 0, 0, 0.2);
transform: translateX(-50%) translateY(-2px);
}
.zoom-btn {
width: 40px;
height: 40px;
padding: 0;
border-radius: 50%;
background: #fff;
border: 1px solid #e8e8e8;
color: #333;
transition: all 0.2s ease;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.zoom-btn:hover {
background: #1989fa;
color: #fff;
border-color: #1989fa;
transform: scale(1.1);
box-shadow: 0 4px 12px rgba(25, 137, 250, 0.3);
}
.zoom-btn:active {
transform: scale(0.95);
}
.zoom-level {
font-size: 14px;
font-weight: 600;
color: #333;
text-align: center;
min-width: 50px;
padding: 8px 12px;
background: rgba(25, 137, 250, 0.1);
border-radius: 20px;
border: 1px solid rgba(25, 137, 250, 0.2);
}
/* 加载遮罩样式 */
.wrapper {
display: flex;
...
...
Please
register
or
login
to post a comment