- 项目新需求要求实现预览用户上传的pdf文件并且要有翻书效果。 找了很多文章参考,最终使用pdfjs+turn.Js实现。
- 安装pdfjs插件
sql
npm install pdfjs-dist@2.2.228 --legacy-peer-deps
2.在需要使用的页面引入
javascript
import * as pdfjs from 'pdfjs-dist'
import * as pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry'
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker
- 由于turn.js依赖JQ,所我们先安装JQ
css
npm install jquery --save
- 配置JQ
- 在vue.config.js中找到module.exports加入代码
css
plugins: [
new webpack.ProvidePlugin({
jQuery: "jquery",
$: "jquery"
})],
结果如图:
5. 在需要使用的页面引用JQ(如果$报错可以试试在main.js中引入)
javascript
import $ from 'jquery'
- 去官网下载turn.Js
- 官网地址:www.turnjs.com/
- 下载成功后解压包,将文件夹里的turn.js和turn.min.js引入项目。(我是放在utils文件夹里面,下图)
- 同样,在需要使用的页面中引入
arduino
import turn from '@/utils/turn.js'
- 东西都准备好后,准备一个pdf文件(一般由后端接口返回,这里我使用的是本地文件)
- 本地文件要放进public文件夹中,访问的时候使用"/static/xxx/xxx"的方式(如下图)
- 准备一个id为flipbook的盒子用来渲染pdf书(相当于一个书壳)里的的div盒子用来循环渲染这本书的每一页
ini
<div id="flipbook">
<div v-for="(item, index) in pdfPicturePath" :key="index" class="page" v-show="show">
<img style="width: 100%; height: 100%" :src="item" />
</div>
</div>
10.handlePdf函数。
- 主要用来下载pdf。
- 然后将pdf的每一页都转换成一张图片并将每一张图片放进一个数组中(pdfPicturePath)
- 数据都准备好后就可以初始化turn.js生成一本书
ini
// fileUrl = "/static/pdf/test.pdf" 这里是本地文件的地址
async handlePdf(fileUrl) {
let that = this
// 下载pdf文件
const pdf = await pdfjs.getDocument(fileUrl);
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
// 循环将pdf每一页转成图片后放入图片列表
for (let i = 1; i <= pdf._pdfInfo.numPages; i++) {
const page = await pdf.getPage(i);
const viewport = page.getViewport({scale: 1});
canvas.width = viewport.width;
canvas.height = viewport.height;
let renderContext = {
canvasContext: context,
viewport: viewport,
};
await page.render(renderContext).promise;
let imgUrl = canvas.toDataURL('image/png')
that.pdfPicturePath.push(imgUrl)
}
this.show = true
// 初始化turn.js生成一本书
$("#flipbook").turn({
acceleration: true, //启用硬件加速,移动端有效
display: 'double', //显示:single=单页,double=双页,默认双页
width: 375, // 书的宽度
height: 627, // 书的高度
autoCenter: true,
turnCorners: 'bl,br', // 设置可翻页的页脚
});
},
- 最后在钩子函数里调用就好了。
- 如果想要点击"下一页""上一页"来翻页,那就直接放两个按钮分别添加点击事件。
javascript
// 上一页
next() {
$("#flipbook").turn("next");
},
// 下一页
previous() {
$("#flipbook").turn("previous");
},
- 最终效果
- 附上整体代码
xml
<template>
<div>
<div id="flipbook">
<div v-for="(item, index) in pdfPicturePath" :key="index" class="page" v-show="show">
<img style="width: 100%; height: 100%" :src="item" />
</div>
</div>
<div style="margin-top: 2rem">
<el-button type="" @click="next">下一页</el-button>
<el-button type="" @click="previous">上一页</el-button>
</div>
</div>
</template>
<script>
import * as pdfjs from 'pdfjs-dist'
import * as pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry'
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker
import $ from 'jquery'
import turn from '@/utils/turn.js'
export default {
name: 'test_box1',
data() {
return {
pdfPicturePath: [],
fileUrl: '/static/pdf/test.pdf',
show: false
}
},
mounted() {
this.handlePdf(this.fileUrl)
},
methods:{
next() {
$("#flipbook").turn("next");
},
previous() {
$("#flipbook").turn("previous");
},
async handlePdf(fileUrl) {
let that = this
const pdf = await pdfjs.getDocument(fileUrl);
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
for (let i = 1; i <= pdf._pdfInfo.numPages; i++) {
const page = await pdf.getPage(i);
const viewport = page.getViewport({scale: 1});
canvas.width = viewport.width;
canvas.height = viewport.height;
let renderContext = {
canvasContext: context,
viewport: viewport,
};
await page.render(renderContext).promise;
let imgUrl = canvas.toDataURL('image/png')
that.pdfPicturePath.push(imgUrl)
}
this.show = true
$("#flipbook").turn({
width: 375,
height: 627,
display: 'single',
autoCenter: true,
turnCorners: 'bl,br',
});
}
}
};
</script>
<style lang="scss" scoped="scoped">
.hard{
text-align: center;
}
.page {
background: pink;
text-align: center;
}
</style>