首页 前端知识 使用pdfjs获取pdf目录以及预览pdf,点击目录滚动到对应的位置

使用pdfjs获取pdf目录以及预览pdf,点击目录滚动到对应的位置

2024-04-29 12:04:15 前端知识 前端哥 306 400 我要收藏

页面的最终效果,

根据静态的pdf自动生成左侧pdf目录,右侧使用pdfjs预览,点击左侧目录,右侧滚动到pdf对应的页面,
(注意:pdf必须包含目录页面,否则无法生成目录)
在这里插入图片描述

然后我们放一下页面的代码

以下代码为vue实现,react的话需要做一下修改,主要在于jspdf中api的调用,pdfjs几乎没有文档

当前使用的pdfjs-dist版本为 2.16.105
“pdfjs-dist”: “^2.16.105”,

<template>
  <div class="margin-box" v-loading="loading">
    <div class="document-directory">
      <span class="directory-title"> 目录 </span>
      <div class="directory-tree">
        <!-- 目录渲染 -->
        <el-tree 
        :data="treeData.outline" 
        :default-expand-all="true" 
        :expand-on-click-node="false"
        :props="treeData.defaultProps" @node-click="data=>navigateTo(data.dest)">
        </el-tree>
      </div>
    </div>
    <!-- pdf渲染 -->
    <div class="PDF-content pdf-container" ref="pdfContainer">
    </div>
  </div>
</template>

<script>
import * as PdfJs from "pdfjs-dist/legacy/build/pdf.js";
import { getDocument } from "pdfjs-dist";
PdfJs.GlobalWorkerOptions.workerSrc = require("pdfjs-dist/build/pdf.worker.entry");

async function getPdf(src) {
  const loadingTask = getDocument({
  url: src,
  disableFontFace: true,   //禁用文本抗锯齿 ,提高渲染性能
});
  const pdf = await loadingTask.promise;
  return pdf;
}

export default {
  name: "PdfViewer",
  props: {
    src: String,
  },
  data() {
    return {
      pdf: null,
      numPages: 0,
      treeData:{
        outline:[],
        defaultProps:{
          children: 'items',
          label: 'title'
        }
      },
      loading:false,
      fragment: document.createDocumentFragment()
    };
  },
  mounted() {
    this.loadPdf(this.src);
  },
  methods: {
    async loadPdf(src) {
      this.loading = true

      // 注意,此处接受的src必须是浏览器可以直接访问pdf的路径
      const pdf = await getPdf(src);
      this.pdf = pdf;

      // 获取pdf的也页数
      this.numPages = pdf.numPages;

      this.renderAllPages();

      this.renderOutline(pdf);
    },
    //渲染整个pdf
    async renderAllPages() {
      for (let i = 1; i <= this.numPages; i++) {
        // 通过文档碎片统一渲染提高性能

        // 插入每一页的pdf渲染
        this.fragment.appendChild(await this.renderPage(i));
      }
      this.$refs.pdfContainer.appendChild(this.fragment);

      this.loading = false
    },
    // 获取目录树
    async renderOutline(pdf) {
      const outline = await pdf.getOutline();
      this.treeData.outline = outline
    },
    // 渲染某页页pdf
    async renderPage(pageNumber) {
      if (!this.pdf) {
        return;
      }

      const page = await this.pdf.getPage(pageNumber);

      // 设置清晰度
      const viewport = page.getViewport({ scale: 2 });

      const canvas = document.createElement("canvas");
      canvas.id = `page-${pageNumber}`;
      canvas.width = viewport.width;
      canvas.height = viewport.height;

      const ctx = canvas.getContext("2d");
      const renderContext = {
        canvasContext: ctx,
        viewport: viewport,
      };

      await page.render(renderContext).promise;

      return canvas
    },
    // 点击跳转到某页
    async navigateTo(dest) {
      if (!this.pdf || !dest) {
        return;
      }

      // 获取目标页面的页码
      const pageNumber = (await this.pdf.getPageIndex(dest[0])) + 1;

      // 滚动到目标页面
      const pageElement = document.getElementById(`page-${pageNumber}`);
      if (pageElement) {
        pageElement.scrollIntoView({ behavior: "smooth" });
      }
    },
  },
};
</script>

<style scoped>
.margin-box {
  box-sizing: border-box;
  margin: 10px;
  height: 95%;
  display: flex;
}
.document-directory {
  width: 400px;
  background-color: #fff;
  height: 100%;
  padding: 20px;
  overflow: auto;
}
.directory-title {
  display: inline-block;
  font-size: 18px;
  margin-bottom: 20px;
}
.PDF-content {
  flex: 1;
  height: 100%;
  overflow: auto;
  background: #eff;
  display: flex;
  flex-direction: column;
  margin:0 10px;
}
/deep/.el-tree-node.is-current > .el-tree-node__content {
    color: #cc2722 !important;
    font-weight: 600;
}
/deep/.el-tree-node:focus>.el-tree-node__content{
  background-color:#fff !important;
}
/deep/.el-tree-node__content:hover{
  background-color:#fff !important;
}
/deep/.el-icon-caret-right:before {
    content: "";
}
/deep/.el-tree-node__content{
  height: 40px;
}
/deep/.el-tree-node__label{
  line-height: 40px;
}
</style>


转载请注明出处或者链接地址:https://www.qianduange.cn//article/6402.html
标签
pdf
评论
发布的文章

HTML5本地存储

2024-05-06 09:05:10

HTML5和CSS3新特性

2024-04-16 17:04:36

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!