pdfjs-dist实现pdf简单预览功能

1,072 阅读1分钟

功能描述:实现pdf的预览,以及一些简单的功能:翻页,下载,放大,缩小

详细使用过程

1.下载插件

npm install --save pdfjs-dist@2.0.943

最好指定一下这个版本,不要用最新的,容易出错

2.上代码

新建一个vue文件,如viewPDF.vue

<template>
    <div class="pdf-wrap">
        <div class="contral">
            <div class="changePage">
                <svg-icon @click="prev" class="icon" icon-class="arrow-up" style="width: 16px; height: 16px"></svg-icon>
                <svg-icon @click="prev" class="icon" icon-class="arrow-down" style="width: 16px; height: 16px"></svg-icon>
                <span class="page">{{pageNum}} / {{pageCount}}页</span>
            </div>
            <div class="title">来瞧瞧pdf</div>
            <div class="func">
                <span>下载</span>
            </div>
        </div>
        <div class="content" id="pdfContent"></div>
        <div class="reading">
            <a-button>已阅读</a-button>
        </div>
    </div>
</template>
<script>
    import * from PDF from 'pdfjs-dist'
    import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry'
    PDF.globalWorkerOptions.workerSrc = pdfjsWorker
    PDF.disabledWorker = true
    export default{
        props: {
            filePath: String,
            fileName: String
        },
        data(){
            return {
                pdfDoc: null, // pdf读取的页面信息
                pageNum: 0, // 当前页数
                pageCount: 0, // 总页数
                pageRendering: false, // 当前页面是否渲染
                pageNumPending: null, // 将要进行渲染的页面页数
                time: 20, // 阅读时间
            }
        },
        methods: {
            loadFile(filePath){
                PDF.getDocument(filePath).then(pdf => {
                    this.pageNum = 1
                    this.pdfDoc = pdf
                    this.pageCount = pdf.numPages
                    this.$nextTick(() => {
                        this.renderPage(this.pageNum)
                    })
                })
            },
            renderPage(num){
                this.pdfDoc.getPage(num).then(page => {
                    let canvas = document.createElement('canvas')
                    let ctx = canvas.getContext('2d')
                    let dpr = window.devicePixelRatio || 1 // 设备像素比,用来解决canvas的清晰度问题
                    let bsr = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio ||
                    ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.BackingStorePixelRatio // 浏览器在渲染canvas之前会用几个像素比来存贮画布
                    let ratio = dpr / bsr
                    let viewport = page.getViewPort(1)
                    canvas.width = viewport.width * ratio
                    canvas.height = viewport.height * ratio
                    ctx.fillStyle = 'rgba(255,255,255,0)'
                    canvas.style.width = viewport.width + 'px'
                    canvas.style.height = viewport.height + 'px'
                    let renderContext = {
                        canvasContext: ctx,
                        viewport: viewport
                    }
                    page.render(renderContext).promise.then(() => {
                        ctx.fillRect(0,0, canvas.width, canvas.height) // fillRect绘制填充的矩形(x,y,width,height),默认填充黑色,结合上面的ctx.fillStyle设置填充白色
                        // 动态绘制canvas,如果存在canvas,则销毁,重新渲染
                        const domCanvas = document.querySelector('canvas')
                        const domPdfContext = document.querySelector('#pdfContent')
                        if(domCanvas) domPdfContext.removeChild(domCanvas)
                        domPdfContext.appendChild(domCanvas)
                        this.pageRendering = false
                        // 如果有未渲染的下一页,则渲染下一页
                        if(this.pageNumPending != null){
                            this.renderPage(this.pageNumPending)
                            this.pageNumPending = null
                        }
                    })

                })
            },
            // 上一页
            prev(){
                if(this.pageNum <= 1){
                    return
                }
                this.pageNum--
                this.waitRenderPage(this.pageNum)
            },
            // 下一页
            next(){
                if(this.pageNum >= this.pageCount){
                    return
                }
                this.pageNum++
                this.waitRenderPage(this.pageNum)
            },
            // 改变渲染页面
            waitRenderPage(num){
                const n = Number(num)
                if(this.pageNumPending){
                    this.pageNumPending = n
                }else {
                    this.renderPage(n)
                }
            },
            // 下载文件
            downLoad(){
                let a = document.createElement('a')
                a.downLoad = this.fileName
                a.href = this.filePath
                a.style.display = 'none'
                document.body.appendChild(a)
                a.click()
                document.removeChild(a)
            },
            // 放大和缩小有时间再补充吧
        }
    }
    </script>
<style lang="less" scoped>
    .pdf-wrap{
        width: 1200px;
        .contral{
            height: 64px;
            display: flex;
            line-height: 64px;
            font-size: 14px;
            color: #0a0c10;
            font-weight: 400;
            border: 1px solid rgba(228, 230, 234, 1);
            .changePage{
                width: 33.3%;
                text-align: right;
                .icon{
                    margin-right: 16px;
                }
            }
            .title{
                width: 33.3%;
                font-size: 20px;
                color: #0a0c10;
                font-weight: 500;
                text-align: center;
            }
            .func{
                width: 33.4%;
                text-align: right;
                padding-right: 96px;
            }
        }
        .tontent{
            height: calc(100vh - 100px);
            background-color: #f1f2f6;
            overflow-y: auto;
        }
        .reading{
            text-align: center;
            margin-top: 10px;
        }
    }
    </style>

好了,重点就结束了,可以在需要的地方进行展示,调用这个组件的时候注意两点:

  1. 父组件传入自定义参数fileName和filePath哦;
  2. 不要忘记父组件要调用子组件的方法loadFile方法

tip: 代码里面有图片,分别是上一页和下一页,不重要,换掉他!


有关canvas的绘制,其中devicePixelRatio和webkitBackingStorePixelRatio,也想要记录一下,期待下一篇文章吧

以上内容也是根据需要参考借鉴了很多大佬的,感谢!