vue实现预览pdf

PC端

直接使用iframe嵌套即可

<iframe
    class="course-file-iframe"
    :src="url"
></iframe>

url就是pdf的线上文档地址
不过我们项目后端并不给返回地址,只返回一个key 然后让前端用这个key去走下载链接来下载这个文件,因此我这里是请求blob二进制流文件,相当于存储到当前浏览器中,然后展示

request.get(apis.url.fileDownload, {
     params: {key: fileKey},
     // 请求类型为blob格式的二进制文件流
     responseType: 'blob',
 }).then(res => {
     // 获取到的blob类型文件地址  pdf文件对应的MIME类型为'application/pdf'
     let type = 'application/pdf';
     const blob = new Blob([res], {type});
     // 这就是blob类型文件地址 赋值给src即可展示(仅限PC端)
     this.url = window.URL.createObjectURL(blob);
 }).catch(err => {
     console.error('文件获取失败', err);
 });

H5端

h5端 用iframe 展示pdf的话 会提示 no enabled plugin supports this MIME typevue实现预览pdf_第1张图片

因此 h5端只能引入第三方插件实现

方案一:vue-pdf

优点:代码少 写的快
缺点:
1. 是以canvas画出来的图片实现的 因此文件中的链接无法点击 (目前我没能解决)
2. 页面能渲染出来,就是控制台报错 没有catch这个属性 (切换版本解决 npm i [email protected]
3. 好像说是还有什么付费字体无法展示之类的,我没有遇到,可能需要各位自己遇到的时候自己找了

<div
    v-else-if="isLocalFile"
    class="course-file-iframe"
>
    <pdf
        v-for="index in numPages"
        :key="index"
        :src="pdfUrl"
        :page="index"
    />
</div>
import Pdf from 'vue-pdf';

export default {
    components: {
        Pdf
    },
    data() {
        return {
        	numPages: null,
            pdfUrl: '',
        }
    }methods: {
    	// 请求pdf文件地址的方法,每个人每个项目都不一样, 按自己的来
    	getUrl() {
    		request.get(api.fileGeneralDownload, {
                    params: {key: fileKey},
                    responseType: 'blob',
                }).then(res => {
                    let type = 'application/pdf';
                    const blob = new Blob([res], {type});
                    this.videoUrl = window.URL.createObjectURL(blob);
                    this.loadPdf();
                }).catch(err => {
                    console.error('文件获取失败', err);
                });
         },
         // 上下滚动pdf加载
        loadPdf() {
            this.pdfUrl = Pdf.createLoadingTask(this.videoUrl);
            this.pdfUrl.promise.then(pdf => {
                this.$nextTick(() => {
                    this.numPages = pdf.numPages; // pdf总页数
                });
            });
        },
    }
}
<style lang="less" scoped>
.course-file-iframe {
    width: 100%;
    height: calc(100% - 45px);
    border: none;
    overflow: auto;
}
</style>

方案二:pdfjs-dist

缺点:
1. 也是以canvas画出来的图片实现的 因此文件中的链接无法点击 (目前我没能解决)
2. 好像也说是还有什么付费字体无法展示之类的,我没有遇到,可能需要各位自己遇到的时候自己找了

<div class="course-file-iframe">
    <canvas
        v-for="page in pages"
        :id="'the-canvas' + page"
        :key="page"
    ></canvas>
</div>
const PDFJS = require('pdfjs-dist');
PDFJS.GlobalWorkerOptions.workerSrc = require('pdfjs-dist/build/pdf.worker.min');

export default {
    data() {
        return {
        	pdfDoc: null,
            pages: 0,
            pdfUrl: '',
            src: '',
            loadding: true,
            file: true,
            isDestory: true
        }
    }methods: {
    	// 请求pdf文件地址的方法,每个人每个项目都不一样, 按自己的来
    	getUrl() {
    		request.get(api.fileGeneralDownload, {
                    params: {key: fileKey},
                    responseType: 'blob',
                }).then(res => {
                    let type = 'application/pdf';
                    const blob = new Blob([res], {type});
                    this.videoUrl = window.URL.createObjectURL(blob);
                    this.loadFile(this.videoUrl);
                }).catch(err => {
                    console.error('文件获取失败', err);
                });
         },
         renderPage(num) {
            // getPage 处理每个页面
            // 返回单页内容实例(页面引索) pdf.getPage(index)
            this.pdfDoc.getPage(num).then(page => {
                // canvas 绘制 PDF
                let canvas = document.getElementById('the-canvas' + num)
                let ctx = canvas.getContext('2d');
                ctx.mozImageSmoothingEnabled = false;
                ctx.webkitImageSmoothingEnabled = false;
                ctx.msImageSmoothingEnabled = false;
                ctx.imageSmoothingEnabled = false;
                let dpr = window.devicePixelRatio || 1;
                let bsr = ctx.webkitBackingStorePixelRatio
                    || ctx.mozBackingStorePixelRatio
                    || ctx.msBackingStorePixelRatio
                    || ctx.oBackingStorePixelRatio
                    || ctx.backingStorePixelRatio
                    || 1;
                let ratio = dpr / bsr;
                // 这里我一直没有获取到宽高 百度了很多都不对 最后才发现是传参的问题 具体分析看下面的遇到的坑
                let viewport = page.getViewport(1);
                canvas.width = viewport.width * ratio;
                canvas.height = viewport.height * ratio;
                canvas.style.width = '100%';
                canvas.style.height = 'calc(100% - 50px)';
                let renderContext = {
                    canvasContext: ctx,
                    viewport: viewport,
                    transform: [ratio, 0, 0, ratio, 0, 0]
                };
                const that = this;
                page.render(renderContext).promise.then(() => {
                    if (that.isDestory) {
                        if (that.pages > num) {
                            that.renderPage(num + 1);
                        }
                    }
                });
            });
        },
        loadFile(url) {
            PDFJS.getDocument(url).promise.then(pdf => {
                this.pdfDoc = pdf;
                this.pages = this.pdfDoc.numPages;
                this.loadding = false;
                const that = this;
                if (that.isDestory) {
                    this.$nextTick(() => {
                        this.renderPage(1);
                    });
                }
            }).catch(err => {
                console.log('err', err);
            });
        },
    }
}

遇到的坑

pdfjs-dist 我getViewport 一直拿不到宽高 NaN (我的版本号就是2.0.943)

网上说改版本号啥的 都不对
最后我看了看node_module里的源码才发现传参错了

vue实现预览pdf_第2张图片他只有一个形参 scale。 并不是github里 issue里说的 那样有三个参数或者是个对象

高版本的可能需要自己看一下源码,2.0.943 版本的只用穿一个scale就行了 ,像我之前传的是一个对象的话 就会导致 pdf倒置 且拿不到宽高 ,改成一个值之后 就正常展示了

你可能感兴趣的:(vue.js,pdf,javascript)