Web-移动端-PDF展示组件

290 阅读4分钟

介绍

因为公司大量涉及OCR等业务,需要支持对PDF或者其他文档类型的展示、交互或标注等操作,所以研究了PDF.js与pdfjs-dist的源码,并基于此开发了相关的PDF组件

主要分为:

  • core包,core提供了PDF类(但是这部分还没有提供出来),其实开发者可以根据这个类自己随意定制您想要的任何PDF展示的toolbar
  • Vue3版本的PDF展示组件: pdf-viewer-vue3
  • Vue2版本的PDF展示组件: pdf-viewer-vue2

如果您想在React、原生Js等架构中展示PDF,可以使用core包(未来会开放)

功能点

文本选中、复制

文本选中.jpg

缩略图

缩略图.jpg

目录

目录.jpg

单页/双页视图

双页视图.jpg

缩放(原尺寸、适应高度、适应宽度、自定义尺寸)

缩放.png

搜索文本

搜索文本优化为切片搜索,不会因为1000页的pdf搜索造成初始化卡顿

搜索.jpg

响应式/移动端(小尺寸容器或者屏幕)

基础.jpg

小尺寸容器:屏幕.png

翻页、跳转页

旋转

旋转.png

横向滚动、竖向滚动

横向滚动.png

打印

主题

默认主题有light、dark,用户可以自定义主题

主题-1.png

主题-2.png

自定义主题如下使用中theme属性

使用

Vue3

<script setup>
import { ref } from 'vue';
import PDF from 'pdf-viewer-vue3';
import 'pdf-viewer-vue3/package/pdf-viewer.css';
const fileInput = ref();
const pdfComp = ref();
const pdfMobileComp = ref();
const theme = ref("light");
async function handleFileChange(event) {
  const files = event.target.files;
  const file = files[0];
  if (file) {
    // loadFile支持buffer数据,也支持解决了跨域问题的文件地址链接(cors支持的文件地址或者在您的项目中nginx代理转发的下载地址都可以)
    const buffer = await file.arrayBuffer();
    pdfMobileComp.value?.loadFile(buffer);
    const reReadBuffer = await file.arrayBuffer();
    pdfComp.value?.loadFile(reReadBuffer);
    
    console.log(pdfComp.value);
  }
}
function openFile() {
  fileInput.value?.click();
}
function customTheme() {
  theme.value = {
    '--pdf-toolbar-bg': '#ccc',
    '--pdf-toolbar-input-bg': '#141414',
    '--pdf-toolbar-text-color': '#EBEBEB',
    '--pdf-toolbar-text-highlight': 'rgb(99 102 241)',
    '--pdf-toolbar-bg-highlight': '#39383D',
    '--pdf-show-bg': '#39383D',
    '--pdf-thumbnail-bg': '#222',
    '--pdf-thumbnail-border-color': '#39383D',
    '--pdf-thumbnail-text-color': '#EBEBEB',
    '--pdf-thumbnail-text-color-highlight': 'rgb(99 102 241)',
    '--pdf-catalogue-text-color': '#EBEBEB',
    '--pdf-catalogue-text-highlight': 'rgb(99 102 241)',
    '--pdf-menu-setting-color': '#EBEBEB',
    '--highlight-bg-color': 'rgba(230, 0, 120, 1)',
    '--highlight-selected-bg-color': 'rgba(100, 0, 0, 1)',
    '--pdf-mask-bg-color': 'rgba(34, 34, 34, .9)',
    '--pdf-mask-process-bg-color': '#D7D7E0',
    '--pdf-mask-process-highlight': 'rgb(167 139 250)',
    '--pdf-mask-tip-color': 'rgb(107 114 128)',
    '--pdf-mask-btn-color': 'rgb(167 139 250)',
    '--pdf-mask-btn-highlight': 'rgb(192 132 252)'
  }
}
</script>

<template>
  <div>
    <button @click="openFile">选择文件</button>
    <button @click="theme = 'dark'">黑色主题</button>
    <button @click="theme = 'light'">浅色主题</button>
    <button @click="customTheme">自定义主题</button>
    <input v-show="false" ref="fileInput" type="file" @change="handleFileChange">
    <p>左侧为大尺寸工具栏,右侧为小尺寸工具栏</p>
    <div 
      style="display: flex;"
    >
      <PDF
        ref="pdfComp"
        :theme="theme"
        @pagesLoaded="(v) => console.log('pagesLoaded', v)"
        @pageRendered="(v) => console.log('pageRendered', v)"
        @pageChanging="(v) => console.log('pageChanging', v)"
        @findChange="(v) => console.log('findChange', v)"
        @scaleChanging="(v) => console.log('scaleChanging 缩放比例改变', v)"
        style="width: 800px; height: 500px; margin: auto;"
      ></PDF>
      <PDF
        ref="pdfMobileComp"
        :theme="theme"
        @pagesLoaded="(v) => console.log('pagesLoaded', v)"
        @pageRendered="(v) => console.log('pageRendered', v)"
        @pageChanging="(v) => console.log('pageChanging', v)"
        @findChange="(v) => console.log('findChange', v)"
        @scaleChanging="(v) => console.log('scaleChanging 缩放比例改变', v)"
        style="width: 300px; height: 500px; margin-left: 20px;"
      ></PDF>
    </div>
    
  </div>
</template>

<style scoped>

</style>

Vue2

<template>
  <div id="app">
    <div>
      <button @click="openFile">选择文件</button>
      <input v-show="false" ref="fileInput" type="file" @change="handleFileChange">
      <button @click="theme = 'dark'">黑色主题</button>
      <button @click="theme = 'light'">浅色主题</button>
      <button @click="customTheme">自定义主题</button>
      <PDF
        ref="pdfComp"
        :theme="theme"
        style="width: 100%; height: 600px; margin: auto;"
      ></PDF>
      <PDF
        ref="pdfMobileComp"
        :theme="theme"
        @pagesLoaded="(v) => log('pagesLoaded', v)"
        @pageRendered="(v) => log('pageRendered', v)"
        @pageChanging="(v) => log('pageChanging', v)"
        @findChange="(v) => log('findChange', v)"
        @scaleChanging="(v) => log('scaleChanging 缩放比例改变', v)"
        style="width: 300px; height: 700px; margin-left: 20px; margin-bottom: 500px;"
      ></PDF>
    </div>
  </div>
</template>

<script>
import PDF from 'pdf-viewer-vue2';
import 'pdf-viewer-vue2/package/pdf-viewer.css';

export default {
  name: 'App',
  components: {
    PDF
  },
  data() {
    return {
      theme: "light"
    }
  },
  methods: {
    async handleFileChange(event) {
      const files = event.target.files
      const file = files[0]
      console.log(file, "File")
      if (file) {
        // loadFile支持buffer数据,也支持解决了跨域问题的文件地址链接(cors支持的文件地址或者在您的项目中nginx代理转发的下载地址都可以)
        const buffer = await file.arrayBuffer()
        this.$refs.pdfMobileComp?.loadFile(buffer);
        const reReadBuffer = await file.arrayBuffer()
        this.$refs.pdfComp?.loadFile(reReadBuffer)
      }
    },
    openFile() {
      this.$refs.fileInput?.click();
    },
    log(name, v) {
      console.log(name, v)
    },
    customTheme() {
      this.theme = {
        '--pdf-toolbar-bg': '#ccc',
        '--pdf-toolbar-input-bg': '#141414',
        '--pdf-toolbar-text-color': '#EBEBEB',
        '--pdf-toolbar-text-highlight': 'rgb(99 102 241)',
        '--pdf-toolbar-bg-highlight': '#39383D',
        '--pdf-show-bg': '#39383D',
        '--pdf-thumbnail-bg': '#222',
        '--pdf-thumbnail-border-color': '#39383D',
        '--pdf-thumbnail-text-color': '#EBEBEB',
        '--pdf-thumbnail-text-color-highlight': 'rgb(99 102 241)',
        '--pdf-catalogue-text-color': '#EBEBEB',
        '--pdf-catalogue-text-highlight': 'rgb(99 102 241)',
        '--pdf-menu-setting-color': '#EBEBEB',
        '--highlight-bg-color': 'rgba(230, 0, 120, 1)',
        '--highlight-selected-bg-color': 'rgba(100, 0, 0, 1)',
        '--pdf-mask-bg-color': 'rgba(34, 34, 34, .9)',
        '--pdf-mask-process-bg-color': '#D7D7E0',
        '--pdf-mask-process-highlight': 'rgb(167 139 250)',
        '--pdf-mask-tip-color': 'rgb(107 114 128)',
        '--pdf-mask-btn-color': 'rgb(167 139 250)',
        '--pdf-mask-btn-highlight': 'rgb(192 132 252)'
      }
    }
  }
}
</script>

<style>
</style>

演示地址

codesandbox.io/p/devbox/ni…

npm包

Vue3版本的PDF展示组件: pdf-viewer-vue3

Vue2版本的PDF展示组件: pdf-viewer-vue2