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 type在这里插入图片描述

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

方案一:vue-pdf

优点:代码少 写的快
缺点:
1. 是以canvas画出来的图片实现的 因此文件中的链接无法点击 (目前我没能解决)
2. 页面能渲染出来,就是控制台报错 没有catch这个属性 (切换版本解决 npm i vue-pdf@4.2.0)
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里的源码才发现传参错了

在这里插入图片描述他只有一个形参 scale。 并不是github里 issue里说的 那样有三个参数或者是个对象
在这里插入图片描述
高版本的可能需要自己看一下源码,2.0.943 版本的只用穿一个scale就行了 ,像我之前传的是一个对象的话 就会导致 pdf倒置 且拿不到宽高 ,改成一个值之后 就正常展示了
在这里插入图片描述

  • 4
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
你可以使用 Vue.js实现预览 PDF 并且可复制的功能。下面是一个简单的示例: 首先,你需要安装 `-pdf` 和 `vue-clipboard2` 两个库。 ```shell npm install vue-pdf vue-clipboard2 ``` 然后,在你的 Vue 组件中,引入并使用这两个库。 ```vue <template> <div> <div> <button @click="copyText">复制</button> </div> <div ref="pdfContainer"> <pdf :src="pdfUrl" @num-pages="setNumPages" @page-loaded="setPageLoaded"></pdf> </div> </div> </template> <script> import { PDF } from 'vue-pdf'; import VueClipboard from 'vue-clipboard2'; export default { components: { PDF, }, data() { return { pdfUrl: 'path/to/your/pdf/file.pdf', numPages: 0, pageLoaded: 0, }; }, methods: { setNumPages(num) { this.numPages = num; }, setPageLoaded(num) { this.pageLoaded = num; }, copyText() { const textToCopy = `当前页码:${this.pageLoaded} / ${this.numPages}`; this.$copyText(textToCopy) .then(() => { // 复制成功 alert('已复制到剪贴板'); }) .catch(() => { // 复制失败 alert('复制失败'); }); }, }, mounted() { VueClipboard.config.autoSetContainer = true; this.$clipboard.$on('success', () => { // 复制成功后的回调 console.log('复制成功'); }); this.$clipboard.$on('error', () => { // 复制失败后的回调 console.log('复制失败'); }); }, }; </script> ``` 在上面的代码中,`pdfUrl` 是你要预览PDF 文件的路径,你可以根据自己的需求进行修改。当用户点击 "复制" 按钮时,会将当前页码信息复制到剪贴板中。 注意:上述代码仅为示例,你可能需要根据你的具体需求进行适当地修改和调整。另外,确保你已经正确引入和注册了 `vue-pdf` 和 `vue-clipboard2` 库。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值