Vue PDF文件预览vue-pdf

   最近做项目, 遇到预览 PDF 这个功能, 在网上找了找, 大多推荐的是 pdf.js, 不过在 Vue 中还是想偷懒直接 npm 组件, 最后找到了一个还不错的 Vue-pdf 组件,GitHub 地址:https://github.com/FranckFreiburger/vue-pdf#readme
不过一般 GitHub 上的注释比较简洁, 所以这里把自己实际使用的过程总结了一下, 下面贴代码
 
 本博客源码: https://github.com/shengbid/vue-demo  这个项目里会把平时博客写的一些功能的代码都放在里面, 有需要可以下载看看, 有帮助的话点个 star 哈
 
引用: npm install --save vue-pdf
 
template 代码:
<template>
  <div class="pdf" v-show="fileType ==='pdf'">
    <p class="arrow">
    // 上一页
    <span @click="changePdfPage(0)" class="turn" :class="{grey: currentPage==1}">Preview</span>
    {{currentPage}} / {{pageCount}}
    // 下一页
    <span @click="changePdfPage(1)" class="turn" :class="{grey: currentPage==pageCount}">Next</span>
    </p>
    // 自己引入就可以使用, 这里我的需求是做了分页功能, 如果不需要分页功能, 只要 src 就可以了
    <pdf
      :src="src" // src 需要展示的 PDF 地址
      :page="currentPage" // 当前展示的 PDF 页码
      @num-pages="pageCount=$event" // PDF 文件总页码
      @page-loaded="currentPage=$event" // 一开始加载的页面
      @loaded="loadPdfHandler"> // 加载事件
    </pdf>
  </div>
</template>
js 代码:<script>  // 引入 PDF
  import pdf from 'vue-pdf'
  export default {components: {pdf},
    data () {
      return {
        currentPage: 0, // pdf 文件页码
        pageCount: 0, // pdf 文件总页数
        fileType: 'pdf', // 文件类型
     src: '', // pdf 文件地址
} },
  created: {
    // 有时 PDF 文件地址会出现跨域的情况, 这里最好处理一下
    this.src = pdf.
createLoadingTask(this.src)
  }
    method: {
      // 改变 PDF 页码,val 传过来区分上一页下一页的值,0 上一页,1 下一页
      changePdfPage (val) {
        // console.log(val)
        if (val === 0 && this.currentPage > 1) {
          this.currentPage--
          // console.log(this.currentPage)
        }
        if (val === 1 && this.currentPage < this.pageCount) {
          this.currentPage++
          // console.log(this.currentPage)
        }
      },
  </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> pdf加载时</span>

loadPdfHandler (e) {
this.currentPage = 1 // 加载的时候先加载第一页
}

}

}

</script>

实际效果

 

问题补充:  文件打印乱码问题解决方法

之前有人问了关于 PDF 打印乱码问题, 我自己试了确实有这个问题, 在官网找了一下, 有人提交了代码解决了这个问题, 现在我把方法附上

原始的打印页面,PDF 格式乱码, 主要是因为 PDF 里使用了自定义字体, 不能识别

 

需要修改 vue-pdf 安装包的 pdfjsWrapper.js 文件

上面后缀为 1 的文件是原始的, 红线框起来的是我修改之后的文件

替换之后, 打印就能正常显示了,

 

 

博客园貌似不能上传文件, 代码太多就不放上来了, 如果有需要可以找我邮箱发你, 或者到官网自己修改文件

git-hup 地址:https://github.com/FranckFreiburger/vue-pdf/pull/130/commits/253f6186ff0676abf9277786087dda8d95dd8ea7,

 

 上面提供的解决文件打印乱码的问题, 实现起来比较麻烦, 而且现在 vue-pdf 的版本已经更新了, 用这个方法可能还会出现空白页的问题. 如果对项目没什么要求, 可用用 iframe 来预览打印, 效果会更好些, 这里把方法放上来, 有需要的可以试试

这里的例子是把 PDF 文件放在 elment 的弹框中, 当然你可以根据你自己的适用场景来决定

html:

<el-dialog
          :close-on-click-modal="false"
          :visible.sync="dialogVisible"
          :fullscreen="true"
          title="文件预览">
          <div class="agreement_picture">
            <div class="pdf">
              <!-- <pdf // 之前的用 PDF 插件的方法
                v-for="i in pdf.numPages"
                :key="i"
                :page="i"
                :src="src">
              </pdf> -->
              // 使用 iframe 方法
              <iframe :src="src" frameborder="0" style="width: 100%; height: 100%"></iframe>
            </div>
          </div>
          <span slot="footer" class="dialog-footer">
            <div class="tip-left transfer">
                <el-button type="info" @click="dialogVisible=false"> 不同意 </el-button>
              <el-button type="danger" @click="agreeSignFun"> 同意 </el-button>
            </div>
          </span>
        </el-dialog>    

js:

  data () {
    return {
      src: '/static/file/ 中国互联网整体网民发展状况——《第 31 次中国互联网发展状况调查报告 (上)》.pdf', //pdf 地址, 这里我用的是我本地的文件, 你也可以使用后台的文件
      dialogVisible: true
    }
  }

 

效果展示:

打印效果:

 

补充内容:

朋友们, 关于跨域问题, 我这里说明一下, 如果你是在本地 localhost 环境请求后台接口返回的文件地址, 一般都会跨域, 报错如下

这个文件地址我在浏览器可以直接打开预览

 

遇到这种问题, 是因为你本地的 localhost 和你后台返回的域名不一致, 可以先用一个本地静态文件调试效果, 在线上环境即通过打包部署的环境 (域名和返回的 PDF 域名一致的环境) 再看效果.

 

另外补充一下打印的问题, 通过 vue-pdf 自带的打印功能, 打印出来的效果一般是这样

 

这个作者在 git 上也说了, 现在 vue-pdf 的打印功能还在试验阶段, 没有完善, 所以寄希望于这个方法实现打印还需一段时日, 上面的内容里我用了 <iframe> 标签来预览打印, 但是现在 iframe 已经不怎么使用了, 有些项目还不允许用, 这里我再补充两种打印方法

1. 先把 PDF 内容转成图片后再打印

<el-dialog
      title="文件预览"
      :visible.sync="dialogVisible"
      width="50%"
    >
      <div ref="printContent">
        <!-- 加载全部页面的 PDF 是循环生成, 不能指定 ref, 不能调用 print 打印方法 -->
        <Pdf
          v-for="i in numPages"
          :key="i"
          :src="src"
          :page="i"
        />
        <!-- 写一个隐藏的 PDF, 用来调用打印 -->
        <Pdf
          v-show="false"
          ref="printPdf"
          :src="src"
        />
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="print">vue-pdf 自带打印 </el-button>
        <el-button type="primary" @click="toImg"> 转图片打印 </el-button>
      </span>
    </el-dialog>
<script>
import Pdf from 'vue-pdf'
import html2canvas from 'html2canvas'
import printJS from 'print-js'

export default {
components: {
Pdf
},
data() {
return {
fileList: [
{
id:
1,
fileName:
'增进函',
fileUrl:
'http://172.16.79.33:8888/group1/.........../rBBPIV7whg2AQNCmAAoc6DKtkwE841.pdf'
},
{
id:
2,
fileName:
'应收账款',
fileUrl: ${window.location.origin}</span>/test1.pdf
}
],
numPages: undefined,
dialogVisible:
false,
src:
'',
printName:
'转图片打印'
}
},
created() {

},
methods: {
// 预览
preview(item) {
this.src = Pdf.createLoadingTask(item.fileUrl)
this.src.promise.then(pdf => {
this.numPages = pdf.numPages
})
this.dialogVisible = true
this.printName = item.fileName
},
// 转图片打印
toImg() {
html2canvas(this.$refs.printContent, {
backgroundColor:
null,
useCORS:
true,
windowHeight: document.body.scrollHeight
}).then((canvas)
=> {
const url
= canvas.toDataURL()
printJS({
printable: url,
type:
'image',
documentTitle:
this.printName
})
// console.log(url)
})
},

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> pdf自带打印</span>

print() {
this.$refs.printPdf.print()
}
}
}

打印效果

 

2. 跳转页面打印, 这种和 iframe 的差不多, 新建一个页面, 调用 window.print() 打印页面, 效果如下

 

 如果以上都不能解决你的问题, 我觉得你可以使用 window.open() 直接新页面打开预览, 使用浏览器自带的打印预览功能.

 

路径问题报错

如果引入文件后,(一般是引入静态文件),PDF 没有展示出来, 并且控制台返回如下

这种情况是你的文件路径不对, 现在使用的 vue 版本大部分都是新版的, 文件夹里去掉了 static 文件, 新增的是 public 文件,

这个问题可以看我的另一篇关于文件路径引用的博客https://www.cnblogs.com/steamed-twisted-roll/p/13278940.html

 

 

现在一般项目为了安全性, 不会直接返回文件地址, 会返回文件流的格式, 对于文件流格式文件可以转化成 blob 文件, 如果有需要可以看下我另一篇博客: 文件流数据如何转 blob 文件 https://www.cnblogs.com/steamed-twisted-roll/p/11821148.html