實際效果
安裝插件
pnpm install vue-pdf-embed
pnpm install vue3-pdfjs
左側pdf菜單組件
<template>
<div class="pdf-view-list">
<div class="item active-item" v-for="(item, index) in pageTotalNum" @click="itemClcik(index)">
<div class="pdf-box">
<vue-pdf-embed :source="testpdf1" class="vue-pdf-embed" :page="index + 1" />
</div>
<div class="page">{{ index + 1 }}</div>
<div class="mask" :class="{ active: activePage === index + 1 }"></div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import VuePdfEmbed from 'vue-pdf-embed';
import { createLoadingTask } from 'vue3-pdfjs/esm'; // 獲得總頁數
import testpdf1 from '@/assets/zhjx-xrkg/testpdf1.pdf';
const props = defineProps<{
activePage: number; // 當前頁
}>();
const emits = defineEmits<{
(event: 'update:activePage', index: number): void;
}>();
const pageTotalNum = ref(0); // 總頁數
onMounted(() => {
// 獲得總頁數
createLoadingTask(testpdf1).promise.then((pdf) => {
pageTotalNum.value = pdf.numPages;
});
});
// 更新當前頁
const itemClcik = (index: number) => {
emits('update:activePage', index + 1);
};
</script>
<style scoped lang="scss">
.pdf-view-list {
width: 183px;
height: 100%;
background-color: #333333;
overflow-y: scroll;
// 隱藏滾動條
&::-webkit-scrollbar {
display: none;
}
.item {
width: 100%;
height: 257px;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 20px 20px 0 20px;
cursor: pointer;
.pdf-box {
width: 140px;
height: 203px;
background: #ffffff;
border-radius: 4px;
z-index: 1;
.vue-pdf-embed {
width: 100%;
height: 100%;
}
}
.page {
font-weight: 600;
font-size: 12px;
color: #ffffff;
line-height: 34px;
z-index: 1;
}
.mask {
width: 100%;
height: 100%;
background-color: transparent;
position: absolute;
left: 0;
top: 0;
z-index: 0;
}
.active {
background-color: #ffaa46;
opacity: 0.2;
}
}
}
</style
右側預覽組件
<template>
<div class="zhjxMain">
<div class="content">
<!-- 展示容器 -->
<div class="left-box" :ref="refs.wrapper" @wheel.prevent="scaleWheel($event)">
<div class="box" :ref="refs.box" @mousedown="dragstart($event)">
<vue-pdf-embed :source="testpdf1" :style="scaleFun" class="vue-pdf-embed" :page="activePage" />
</div>
<div class="zoomin-wrapper">
<img src="@/assets/XRKG/btn-enlarge.svg" @click="rollBtn('enlarge')" alt="" />
<img src="@/assets/XRKG/btn-zoomin.svg" @click="rollBtn('zoomin')" alt="" />
<img src="@/assets/zhjx-xrkg/btn-flip.svg" alt="" @click="rolate" />
</div>
</div>
<div class="right-box">
<div class="item" v-for="(value, key) in parseObj">
<div class="label">{{ key }}</div>
<div class="text">
{{ value }}
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, reactive, watch } from 'vue';
import VuePdfEmbed from 'vue-pdf-embed';
import testpdf1 from '@/assets/zhjx-xrkg/testpdf1.pdf';
const props = defineProps<{
activePage: number;
}>();
const parseObj = ref({
設備名稱: '1RPEOOIBA冷卻劑疏水泵',
功能位置: 'ND-4-01-RGL-010AR',
缺陷原因: `取工作票,現場確認設備位號及安措正確
拆卸聯軸器螺栓,對中複查同軸度 0.08mm平行度0.03mm不合格
拆卸泵蓋螺栓,將泵憋體脫出運至檢修場地,臨時開口設備做好封堵拆卸葉輪及機械密封組件,解體軸承箱,消洗檢查各零部件,測量泵軸最大0.0...大0.02mm,軸與軸承配合間隙最大0.01mm,軸與葉輪配合間隙0.02mm,體口環與葉回裝新軸承及機械密封組件,安裝泵葉輪,將泵整體運往現場回裝,至工作油位,調整對中同軸度 0.03mm平行度 0.025mm,合格
回裝聯軸器及保護單,清理現場
歸還工作票及輻射票完工,修後試驗在工單01447934-02中執行`,
處理措施: `1RPB002P0 解體檢查工作完成`,
處理結果: `取工作票,現場確認設備位號及安措正確
拆卸聯軸器螺栓,對中複查同軸度 0.08mm平行度0.03mm不合格
拆卸泵蓋螺栓,將泵憋體脫出運至檢修場地,臨時開口設備做好封堵拆卸葉輪及機械密封組件,解體軸承箱,消洗檢查各零部件,測量泵軸最大0.0...大0.02mm,軸與軸承配合間隙最大0.01mm,軸與葉輪配合間隙0.02mm,體口環與葉回裝新軸承及機械密封組件,安裝泵葉輪,將泵整體運往現場回裝,至工作油位,調整對中同軸度 0.03mm平行度 0.025mm,合格
回裝聯軸器及保護單,清理現場
歸還工作票及輻射票完工,修後試驗在工單01447934-02中執行`,
其他字段1: `取工作票,現場確認設備位號及安措正確
拆卸聯軸器螺栓,對中複查同軸度 0.08mm平行度0.03mm不合格
拆卸泵蓋螺栓,將泵憋體脫出運至檢修場地,臨時開口設備做好封堵拆卸葉輪及機械密封組件,解體軸承箱,消洗檢查各零部件,測量泵軸最大0.0...大0.02mm,軸與軸承配合間隙最大0.01mm,軸與葉輪配合間隙0.02mm,體口環與葉回裝新軸承及機械密封組件,安裝泵葉輪,將泵整體運往現場回裝,至工作油位,調整對中同軸度 0.03mm平行度 0.025mm,合格
回裝聯軸器及保護單,清理現場
歸還工作票及輻射票完工,修後試驗在工單01447934-02中執行`,
我是很長的字段名稱: `取工作票,現場確認設備位號及安措正確
拆卸聯軸器螺栓,對`,
其他字段2: `取工作票,現場確認設備位號及安措正確
拆卸聯軸器螺栓,對中複查同軸度 0.08mm平行度0.03mm不合格
拆卸泵蓋螺栓,將泵憋體脫出運至檢修場地,臨時開口設備做好封堵拆卸葉輪及機械密封組件,解體軸承箱,消洗檢查各零部件,測量泵軸最大0.0...大0.02mm,軸與軸承配合間隙最大0.01mm,軸與葉輪配合間隙0.02mm,體口環與葉回裝新軸承及機械密封組件,安裝泵葉輪,將泵整體運往現場回裝,至工作油位,調整對中同軸度 0.03mm平行度 0.025mm,合格
回裝聯軸器及保護單,清理現場
歸還工作票及輻射票完工,修後試驗在工單01447934-02中執行`,
其他字段3: `取工作票,現場確認設備位號及安措正確
拆卸聯軸器螺栓,對中複查同軸度 0.08mm平行度0.03mm不合格
拆卸泵蓋螺栓,將泵憋體脫出運至檢修場地,臨時開口設備做好封堵拆卸葉輪及機械密封組件,解體軸承箱,消洗檢查各零部件,測量泵軸最大0.0...大0.02mm,軸與軸承配合間隙最大0.01mm,軸與葉輪配合間隙0.02mm,體口環與葉回裝新軸承及機械密封組件,安裝泵葉輪,將泵整體運往現場回裝,至工作油位,調整對中同軸度 0.03mm平行度 0.025mm,合格
回裝聯軸器及保護單,清理現場
歸還工作票及輻射票完工,修後試驗在工單01447934-02中執行`,
});
// 實現pdf縮放
const scaleFun = computed(() => {
return `transform:scale(${scaleData.scale});transition: all 0.3s;`;
});
const refs = {
wrapper: ref<HTMLElement | null>(null), // pdf外層容器
box: ref<HTMLElement | null>(null), // pdf容器,用於拖拽
};
const dragData = reactive({
x: 0, // 拖拽初始化時的x座標
y: 0, // 拖拽初始化時的y座標
left: 0, // 拖拽結束時的x偏移量
top: 0, // 拖拽結束時的y偏移量
firstX: 0, // 初始x座標
firstY: 0, // 初始y座標
});
const scaleData = reactive({
scale: 1, // 縮放比例
scaleNum: 0.1, // 滾輪縮放比例
scaleMax: 100, // 最大縮放比例
scaleMin: 0.1, // 最小縮放比例
scaleBtn: 0.4, // 縮放按鈕縮放比例
rotate: 0, // 旋轉角度
});
watch(
() => props.activePage,
(v) => {
// 重置pdf大小和位置
scaleData.scale = 1;
scaleData.rotate = 0;
refs.box.value.style.left = '50%';
refs.box.value.style.top = '50%';
boxTransform();
},
);
// box 容器也要跟着變化
const boxTransform = () => {
refs.box.value.style.transform = `translate(-50%, -50%) rotate(${scaleData.rotate}deg) scale(${scaleData.scale})`;
};
// 旋轉
const rolate = () => {
scaleData.rotate += 90;
boxTransform();
};
// 鼠標滾輪縮放
function scaleWheel(e: any) {
let dy = -e.deltaY || e.wheelDeltaY;
if (dy < 0) {
scaleData.scale -= scaleData.scaleNum;
} else {
// console.log('放大');
scaleData.scale += scaleData.scaleNum;
}
// 邊界判斷
if (scaleData.scale >= scaleData.scaleMax) {
scaleData.scale = scaleData.scaleMax;
return;
}
if (scaleData.scale <= scaleData.scaleMin) {
scaleData.scale = scaleData.scaleMin;
return;
}
boxTransform();
return false;
}
// 點擊放大縮小
const rollBtn = (action: 'enlarge' | 'zoomin') => {
if (action === 'enlarge') {
scaleData.scale += scaleData.scaleBtn;
} else {
scaleData.scale -= scaleData.scaleBtn;
}
// 邊界判斷
if (scaleData.scale >= scaleData.scaleMax) {
scaleData.scale = scaleData.scaleMax;
return;
}
if (scaleData.scale <= scaleData.scaleMin) {
scaleData.scale = scaleData.scaleMin;
return;
}
boxTransform();
};
// 拖拽(box容器拖拽)
function dragstart(e: MouseEvent) {
refs.box.value.style.transition = 'none';
e.preventDefault(); // 阻止默認事件
const box = refs.box.value as HTMLElement;
const wrapper = refs.wrapper.value as HTMLElement;
dragData.x = e.pageX - box.offsetLeft;
dragData.y = e.pageY - box.offsetTop;
// 添加鼠標移動事件
document.addEventListener('mousemove', move);
function move(event: any) {
// 計算元素的位置
dragData.left = event.pageX - dragData.x;
dragData.top = event.pageY - dragData.y;
// 邊界判斷可以在這裏添加 ↓
// 設置元素的位置
box.style.left = dragData.left + 'px';
box.style.top = dragData.top + 'px';
}
// 添加鼠標擡起事件,鼠標擡起,將事件移除
document.addEventListener('mouseup', function () {
document.removeEventListener('mousemove', move);
});
// 鼠標離開父級元素,把事件移除
document.addEventListener('mouseout', function () {
document.removeEventListener('mousemove', move);
});
}
</script>
<style scoped lang="scss">
.zhjxMain {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background-color: #000000;
overflow: hidden;
.content {
width: 100%;
height: 100%;
margin: 0 auto;
background-color: #000000;
display: flex;
overflow: hidden;
.left-box {
width: 50%;
height: 100%;
background-color: #262626;
margin-right: 10px;
position: relative;
overflow: hidden;
.box {
width: 80%;
height: 100%;
object-fit: contain;
user-select: none; /* 不可選中,爲了拖拽時不讓文字高亮 */
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: flex;
align-items: center;
justify-content: center;
.vue-pdf-embed {
width: 100%;
}
}
.zoomin-wrapper {
position: absolute;
top: 50%;
right: 20px;
transform: translateY(-50%);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
img {
width: 34px;
height: 34px;
cursor: pointer;
margin: 5px 0;
}
}
.center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.bottom-left {
position: absolute;
bottom: 20px;
left: 20px;
}
}
.right-box {
width: 50%;
height: 100%;
background-color: #000000;
margin-left: 10px;
padding: 10px 0;
overflow-y: scroll;
// 修改滾動條
&::-webkit-scrollbar {
width: 10px;
}
&::-webkit-scrollbar-thumb {
background: #333333;
border-radius: 10px;
}
.item {
min-height: 48px;
display: flex;
padding-right: 50px;
& + .item {
margin-top: 10px;
}
.label {
width: 100px;
min-height: 48px;
display: flex;
align-items: center;
justify-content: center;
color: #ffffff;
font-size: 14px;
font-weight: 600;
padding: 0 5px;
}
.text {
flex: 1;
color: #ffffff;
background-color: #262626;
border-radius: 10px;
font-size: 14px;
font-weight: 600;
line-height: 24px;
padding: 10px 20px;
}
}
}
}
}
</style>
具體請參考鏈接
Vue3 實現 PDF 文件在線預覽功能