先看效果
直接上代码
pnpm install vue-pdf-embed pnpm install vue3-pdfjs
<template>
<div>
<div class="pdf-header">
<div class="pdf-header-btn">
<el-button @click="handleBack"><返回上一页</el-button>
<p class="title">{{ title }}</p>
</div>
<div class="page-tool">
<div class="page-tool-item" @click="setPage(-1)">上一页</div>
<div class="page-tool-item" @click="setPage(1)">下一页</div>
<div class="page-tool-item">{{ state.pageNum }}/{{ state.numPages }}</div>
<div class="page-tool-item" @click="setZoom(0.1)">放大</div>
<div class="page-tool-item" @click="setZoom(-0.1)">缩小</div>
<el-button type="primary" @click="handleDelete">删除</el-button>
</div>
</div>
<div class="pdf-container">
<!-- 目录 -->
<div class="container-left">
<div class="catalogue-item" v-for="i in state.numPages" :key="i">
<div :class="i === state.pageNum ? 'active' : ''">
<vue-pdf-embed
class="item-pdf"
:source="state.source"
:style="scale"
:page="i"
@click="state.pageNum = i"
/>
</div>
<p>{{ i }}</p>
</div>
</div>
<div class="container-right">
<div class="pager-pdf-container">
<vue-pdf-embed
:source="state.source"
:style="scale"
class="pager-pdf"
:page="state.pageNum"
/>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import VuePdfEmbed from "vue-pdf-embed";
import { createLoadingTask } from "vue3-pdfjs";
import { reactive, onMounted, computed } from "vue";
import pdfUrl from "@/assets/jianli.pdf";
const title = "我的简历";
const state = reactive({
source: pdfUrl, // 预览pdf文件地址
pageNum: 1, // 当前页面
scale: 1, // 缩放比例
numPages: 0, // 总页数
});
const scale = computed(() => `transform:scale(${state.scale})`);
const setPage = (page)=> {
if (page > 0 && state.pageNum < state.numPages) {
state.pageNum++;
} else {
if (state.pageNum > 1) {
state.pageNum--;
}
}
}
const setZoom = (val)=> {
if (val > 0 && state.scale < 2) {
state.scale += 0.1;
} else {
if (state.scale > 0.6) {
state.scale -= 0.1;
}
}
}
// 删除
const handleDelete = ()=>{
console.log('删除')
}
// 返回上一页
const handleBack = ()=>{
console.log('返回上一页')
}
onMounted(() => {
const loadingTask = createLoadingTask(state.source);
loadingTask.promise.then((pdf: { numPages: number }) => {
state.numPages = pdf.numPages;
});
});
</script>
<style lang="scss" scoped>
.pdf-header-btn{
display: flex;
align-items: center;
}
.pdf-header {
width: 100%;
height: 60px;
position: fixed;
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
z-index: 999;
padding: 0 20px;
min-width: 1200px;
background-color: #323639;
box-shadow: 0px 0px 3px #c8c8c8;
}
.title {
font-size: 18px;
color: #fff;
margin-left: 20px;
}
.page-tool {
display: flex;
align-items: center;
cursor: #fff;
user-select: none;
.page-tool-item {
padding: 8px 15px;
padding-left: 10px;
cursor: pointer;
}
}
.pdf-container{
display: flex;
margin: 0 auto;
padding-top: 60px;
min-height: calc(100vh - 166px);
.container-left{
width: 300px;
box-sizing: border-box;
height: calc(100vh - 166px);
overflow-y: auto;
background-color: #323639;
.catalogue-item{
width: 200px;
margin: 10px auto;
text-align: center;
cursor: pointer;
p{
margin: 0;
padding: 10px 0;
color: #fff;
}
.item-pdf{
box-sizing: border-box;
width: 190px;
}
.active{
border: 5px solid #7d9dfe;
}
}
}
.container-right{
flex: 1;
height: calc(100vh - 166px);
background-color: #505050;
overflow: scroll;
.pager-pdf-container{
width: 100%;
height: 100%;
overflow: auto;
.pager-pdf{
padding: 50px 0;
width: 800px;
margin: 0 auto;
}
}
}
}
</style>