vue+vite中直接打开pdf文件(插件pdfjs-dist)

2,290 阅读1分钟

效果预览

image.png

  1. 下载插件
npm install pdfjs-dist@2.15.349
  1. 封装组件

2.1 找到node-modules>pdfjs-dist文件夹, 把build、cmaps、web文件夹整个复制到
static>pdf(新建pdf文件夹,把那三个小文件夹复制到这里,一个都不能少!!!!!!)

image.png

2.2 新建第三方封装getPdfjsDist.js 获取文件方法

image.png

const getJavsScript = (src) => {
  return new Promise((resolve, reject) => {
    const script = document.createElement('script')
    script.onload = resolve
    script.onerror = reject

    script.src = src
    document.body.append(script)
  })
}
const getCss = (href) => {
  return new Promise((resolve, reject) => {
    const link = document.createElement('link')

    link.onload = resolve
    link.onerror = reject

    link.setAttribute('rel', 'stylesheet')
    link.setAttribute('type', 'text/css')
    link.href = href
    document.body.append(link)
  })
}
const getPdfjsDist = (pdfjsDistPath) => {
  return getJavsScript(`${pdfjsDistPath}/pdf/build/pdf.js`)
    .then(() => {
      return Promise.all([
        getJavsScript(`${pdfjsDistPath}/pdf/web/pdf_viewer.js`),
        getCss(`${pdfjsDistPath}/pdf/web/pdf_viewer.css`)
      ])
    })
}
export default getPdfjsDist

2.3 预览pdf文件

<template>
  <div>
    <div class="div" v-show="show">
      <div class="tools-bar"><a class="close" @click="close"><van-icon name="cross"></van-icon></a></div>
      <div class="pdf-view">
        <div id="viewerContainer" ref="container">
          <div id="viewer" class="pdfViewer"></div>
        </div>
      </div>
    </div>
  </div>
</template>
<script lang="ts">
import { onMounted, ref, unref, watch } from 'vue'
import getPdfjsDist from './getPdfjsDist'

export default {
  name: 'PdfViewer',
  components: {
    // VuePdfEmbed
  },
  props: {
    show: { type: Boolean, default: false, },
    url: { type: String, default: '' } // pdf文件路径
  },
  setup(props, ctx) {
    let pdfjsDistPath: string = "./static";
    // if (window.location.pathname.endsWith("index.html")) {
    //   pdfjsDistPath = window.location.origin + window.location.pathname.replace("index.html", "") + "static";
    // } else {
    //   pdfjsDistPath = window.location.origin + window.location.pathname + "static";
    // }
    const type = "canvas";
    let pdfViewer: any = null;
    let pdfLinkService: any = null;
    let currentScale = "page-width";
    let loadingTask: any = null;
    let CMAP_URL = "";
    const container = ref();

    async function pdfLibInit() {
      let pdfjsLib = (window as any).pdfjsLib;
      let pdfjsViewer = (window as any).pdfjsViewer;

      if (!pdfjsLib || !pdfjsViewer) {
        try {
          await getPdfjsDist(pdfjsDistPath)
          CMAP_URL = `${pdfjsDistPath}/pdf/cmaps/`;
          pdfjsLib = (window as any).pdfjsLib;
          pdfjsLib.GlobalWorkerOptions.workerSrc = `${pdfjsDistPath}/pdf/build/pdf.worker.js`
          pdfjsViewer = (window as any).pdfjsViewer;
        } catch (error) {
          // console.log(error)
          // pdfjs文件获取失败
          return
        }
      }

      const containerRef = container.value
      const eventBus = new pdfjsViewer.EventBus();
      // (Optionally) enable hyperlinks within PDF files.
      const pdfLinkServiceTmp = new pdfjsViewer.PDFLinkService({
        eventBus: eventBus,
      });
      pdfLinkService = pdfLinkServiceTmp
      const pdfViewerTmp = new pdfjsViewer.PDFViewer({
        container: containerRef,
        eventBus: eventBus,
        linkService: pdfLinkService,
        renderer: type,
        textLayerMode: 0,
        downloadManager: new pdfjsViewer.DownloadManager({}),
        enableWebGL: true
      });
      pdfViewer = pdfViewerTmp
      pdfLinkService.setViewer(pdfViewer);

      eventBus.on("pagesinit", function ({ source }) {
        source.currentScaleValue = currentScale;
      });
    }

    function renderPdf() {
      if (!props.url) {
        return
      }
      // Loading document.
      if (pdfViewer === null || pdfLinkService === null) {
        return
      }
      if (loadingTask !== null) {
        loadingTask.destroy()
        loadingTask = null
      }
      loadingTask = (window as any).pdfjsLib.getDocument({
        // cMapUrl: CMAP_URL, // 原来是相对路径 但是会报错提示字体找不到 后来换了绝对路径 或 线上字体地址 都可以正常使用
        cMapUrl: window.location.origin+ '/static/pdf/cmaps/', // 绝对路径
        // cMapUrl: 'https://unpkg.com/pdfjs-dist@2.15.349/cmaps/', // 线上字体地址
        cMapPacked: true,
        url: props.url,
      });
      return loadingTask.promise.then((pdfDocument) => {
        if (pdfDocument.loadingTask.destroyed || !props.url) {
          return
        }
        pdfViewer.setDocument(pdfDocument)
        pdfLinkService.setDocument(pdfDocument, null);
        loadingTask = null
        ctx.emit('load-ok')
      }).catch(error => {
        console.log(error)
      });
    }

    const close = function () {
      ctx.emit('on-ok', false)
    }

    onMounted(() => {
      pdfLibInit().then(() => {
        renderPdf()
      })
    })

    watch(() => props.url, (newVal, oldVal) => {
      console.log(props.url)
      if (pdfViewer) {
        pdfViewer._cancelRendering()
      }
      renderPdf();
    }, { deep: true })

    return {
      container,
      close,
    }
  }
}
</script>
<style scoped lang="less">
.div {
  top: 50px;
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background-color: #fff;
  z-index: 999;
  overflow: auto;
}

.tools-bar {
  position: fixed;
  top: 50px;
  right: 0;
  left: 0;
  z-index: 9;
  display: flex;
  justify-content: flex-end;

  .close {
    padding: 15px;
    display: flex;
    justify-content: center;
    align-items: center;

    &:before {
      content: "";
      width: 30px;
      height: 30px;
      background-color: rgba(0, 0, 0, .3);
      border-radius: 50%;
    }

    i {
      position: absolute;
      font-size: 1.8rem;
      color: #fff;
    }
  }
}</style>
  1. 使用
<template>
    <div>
        <pdfViewer :show="pdfViewSource.show" :url="pdfViewSource.url" @on-ok="pdfViewSource.show = false"></pdfViewer>
    </div>
</template>
<script type="module" lang="ts">
import pdfViewer from './pdfView/index.vue'
export default defineComponent({
    components: {pdfViewer},
    setup () {
        const filePreviewClick = (source:any)=>{
            let url:any = source.url
            pdfViewSource.url = url
            pdfViewSource.show = true
        }
    }
})
</script>