在electron中实现PDF的在线预览

由于公司业务的开发需要,需要实现在electron上实现PDF的在线预览功能。electron 3.x版本后就不在支持PDF的预览功能了,官方给的解释是由于人手不够将不再支持PDF预览功能(也是醉了),在经过一番调研结合大佬们的经验实现了PDF的在在线预览功能

实现方式一、

  1. 下载pdfjs-dist

  2. 将下好的文件放入static文件目录下

  3. 在electron的主线程中通过渲染线程与主线程之间的通信获取viewer.html文件位置

    // 监听获取viewer.html文件位置、
    function getUrl(win) {
      const filePath = process.env.NODE_ENV === 'development' ? `${__static}\\pdfjs\\web\\viewer.html` : path.resolve(__dirname, '../../../static/pdfjs/web/viewer.html')
      win.webContents.send('recieve', filePath)
    }
    // pdf预览获取viewer.html文件位置
        ipcMain.on('getUrl', () => getUrl(win))
    
  4. 在pdf.vue中写

    <template>
       <iframe
            :src="base + '?file=' + url"
            :width="width"
            :height="height"
            class="iframe-placeholder"></iframe>
    </template>
    <script>
    import { ipcRenderer } from 'electron' // eslint-disable-line
    
    export default {
      props: {
        url: {
          type: String,
          default: '',
        },
        width: {
          type: Number,
          default: 750
        },
        height: {
          type: Number,
          default: 600
        },
      },
      data() {
        return {
          preview: false,
          base: '',
        }
      },
      computed: {
        // 讲义文件名
        name() {
          const uri = decodeURI(this.url)
          const arr = uri.split('/')
          const len = arr.length
          return arr[len - 1]
        },
      },
      created() {
        // 获取viewer.html的位置
        ipcRenderer.send('getUrl')
      },
      mounted() {
        ipcRenderer.on('recieve', (e, arg) => {
          console.log('文件路径', arg)
          this.base = arg
        })
      }
    }
    </script>
    
    <style lang="scss" scoped>
    .wrapper {
      .info {
        width: 200px;
      }
      .iframe-placeholder {
        background: url('../../../assets/loading.svg') no-repeat 50% 50%;
      }
    }
    </style>
    
    
  5. 在需要引入的地方引用即可

问题

样式比较丑,但是可以实现PDF的分页和打印的功能,且在打完包后文件比较大

实现方式二、

  1. 下载npm pdfjs-dist 包

    // npm的下载方式
    npm i pdfjs-dist
    // yarn 的下载方式
    yarn add pdfjs-dist
    
  2. 在webpack的配置中写入

     entry: {
        renderer: path.join(__dirname, '../src/renderer/main.js'),
        'pdf.worker': 'pdfjs-dist/build/pdf.worker.entry',
      },
    
  3. 在pdf.vue中写入

    <template>
      <el-dialog
        :visible.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>
      </el-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)
            .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>
    
  4. 在需要引入的地方引入即可

问题

  • 参考的文档思否 gitHub

实现方式三、

加载 npm i electron-pdf ,由于这种方法会导致新建窗口,故没有做实验

你可能感兴趣的:(electron,学习)