App 端(vue)上实现预览 PDF

方式一:JavaScript 插件实现 pdf 转 html

一、 引入第三方插件 PDF.js

在命令行中:

npm install pdfjs-dist
二、 在 vue.config.js 中定义 pdf.worker

在第三行

const  pages  =  require("./build/pages");
const  path  =  require("path");
//新增此行代码
pages["pdf.worker"] = "./node_modules/pdfjs-dist/build/pdf.worker.entry";

module.exports  = {
    publicPath:  "./",
    assetsDir:  "assets",
    pages:  pages,   
    //以下省略...
三、 编写展示 pdf 的代码,可以做成组件(推荐),也可以直接协助想要展示的页面内

下面给出展示 pdf 的预览弹窗组件:

<template>
  <mu-dialog :open.sync="pdfjsView" title="" width="55%" class="cpdf" append-to-body @close="pdfurl = null">
    <div v-loading="loading" v-if="pdfurl" class="center" style="height: 600px">
      <canvas v-for="data in canvasData" :key="data" :id="'the-canvas-' + data" class="canvasstyle"></canvas>
    </div>
    <div v-else style="font-size: 18px; text-align: center; font-weight: 900">没有PDF文件可以预览</div>
    <span slot="footer">
      <el-button @click="pdfjsView = false">取 消</el-button>
      <el-button type="primary" @click="pdfjsView = false">确 定</el-button>
    </span>
  </mu-dialog>
</template>

<script type="text/ecmascript-6">
import PDFJS from 'pdfjs-dist'

export default {
  name: 'CPdf',
  components: {},
  data() {
    return {
      pdfDoc: null, // pdfjs 生成的对象
      pageNum: 1, //
      pageRendering: false,
      pageNumPending: null,
      scale: 1.2, // 放大倍数
      page_num: 0, // 当前页数
      page_count: 0, // 总页数
      maxscale: 2, // 最大放大倍数
      minscale: 0.8, // 最小放大倍数
      canvasData: [],
      pdfjsView: false,
      pdfurl: null,
      loading: false
    }
  },
  methods: {
    renderPage(num) {
      // 渲染pdf
      const vm = this
      this.pageRendering = true
      const canvas = document.getElementById(`the-canvas-${num}`)
      // Using promise to fetch the page
      this.pdfDoc.getPage(num).then((page) => {
        const viewport = page.getViewport(vm.scale)
        // alert(vm.canvas.height)
        canvas.height = viewport.height
        canvas.width = viewport.width

        // Render PDF page into canvas context
        const renderContext = {
          //   canvasContext: vm.ctx,
          canvasContext: canvas.getContext('2d'),
          viewport
        }
        const renderTask = page.render(renderContext)

        // Wait for rendering to finish
        renderTask.promise.then(() => {
          vm.pageRendering = false
          if (vm.pageNumPending !== null) {
            // New page rendering is pending
            vm.renderPage(vm.pageNumPending)
            vm.pageNumPending = null
          }
        })
      })
      vm.page_num = vm.pageNum
    },
    getUrl(url) {
      this.pdfurl = url
      this.pdfjsView = true
      this.showPDf()
    },
    showPDf() {
      const vm = this
      this.loading = true
      vm.canvasData = []
      // PDFJS.workerSrc = '../../../static/PDF/pdf.worker.min.js'
      PDFJS.getDocument(vm.pdfurl).promise.then((pdfDoc_) => {
        // 初始化pdf
          vm.pdfDoc = pdfDoc_
          vm.page_count = vm.pdfDoc.numPages
          for (let i = 0; i < vm.page_count; i += 1) {
            vm.canvasData.push(i + 1)
          }
          return pdfDoc_
        })
        .then((pdfDoc_) => {
        // 初始化pdf
          vm.pdfDoc = pdfDoc_
          vm.page_count = vm.pdfDoc.numPages
          for (let i = 0; i < vm.page_count; i += 1) {
            vm.renderPage(i + 1)
          }
          vm.loading = false
        })
    }
  },
  computed: {},
  mounted() {
      //
  }
}
</script>

<style lang="scss" scoped type="text/css">
.cpdf {
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 99999;
  display: flex;
  justify-content: center;
  align-items: center;
  .center {
    text-align: center;
    height: 100%;
    overflow: auto;
    padding-top: 20px;
    .contor {
      margin-bottom: 10px;
    }
  }
  .page-foot {
    position: fixed;
    left: 0px;
    bottom: 0px;
    width: 100%;
    height: 56px;
    line-height: 56px;
    background-color: #fff;
    text-align: center;
    z-index: 10;
    .foot-button {
      display: inline-block;
      height: 56px;
      position: relative;
      top: -22px;
      left: 20px;
    }
  }
}
</style>
四、调用(使用)pdf 展示方法

示例为调用 pdf 展示组件:先引入组件,然后调用其中实例方法。

<template>
  <div id="app">
    index
    <mu-button @click="open"> open</mu-button>
    <CPdf ref="pdf" />
    <!-- <mu-button color="primary" @click="getMenu">getMenu</mu-button> -->
  </div>
</template>
<script>
// import http from "../../utils/http.js";
import CPdf from "./pdf.vue";
export default {
  name: "login",
  components: {
    CPdf
  },
  methods: {
    open() {
      this.$refs.pdf.pdfjsView = true;
      this.$refs.pdf.getUrl('https://neilpatel.com/wp-content/uploads/2015/04/marketingplan.pdf');
    }
  }
};
</script>

方式二:使用 apicloud 的 pdf 预览模块

在 vue 组件中使用示例如下:

<template>
  <div id="app">
    <button @click="openPDF" :style="{ marginTop: '50px' }">点击</button>
  </div>
</template>

<script>
export default {
  name: "PdfTest",
  data() {
    return {
      pdfReader: "",
    };
  },
  methods: {
    openPDF() {
      let downloadUrl =
        "http://192.168.40.223:8011/prj-trqz/ext/download/marketingplan.pdf";
      this.pdfReader.open({
        // path: "fs://" + downloadUrl.split("/")[downloadUrl.split("/").length - 1],
        path: downloadUrl,
        backBtn: {
          size: {
            w: 60,
            h: 40,
          },
          bg: {
            normal: "#282828",
            highlight: "#d3d3d3",
          },
          title: {
            text: "关闭",
            size: 13,
            color: "#fff",
          },
          corner: 4,
        },
      });
    },
    clearCache() {
      this.pdfReader.clearCache();
    },
  },
  mounted() {
    this.pdfReader = window.api.require("pdfReader");
  },
};
</script>