Vue3实现PDF目录预览功能

在 Vue 项目中实现 "左侧目录 + 右侧 PDF 文档预览" 的功能,可通过 pdf.js(Mozilla 官方 PDF 解析库) 结合分栏布局来完成。以下是详细的实现步骤和代码示例:

一、技术选型与依赖安装

核心依赖是 pdfjs-distpdf.js 的 npm 包),用于解析 PDF 文档并提取目录、渲染页面。

bash

javascript 复制代码
# 安装依赖
npm install pdfjs-dist

二、组件实现(以 Vue3 为例)

创建 PDFViewer.vue 组件,分为左侧目录栏右侧 PDF 预览区,并实现目录跳转功能。

vue

javascript 复制代码
<template>
  <div class="pdf-viewer-container">
    <!-- 左侧目录 -->
    <div class="toc-column">
      <h3>文档目录</h3>
      <ul class="toc-list">
        <li 
          v-for="item in flattenedToc" 
          :key="item.id" 
          class="toc-item"
          @click="scrollToPage(item.dest)"
        >
          {{ item.title }}
        </li>
      </ul>
    </div>

    <!-- 右侧PDF预览 -->
    <div class="pdf-viewer">
      <canvas 
        v-for="page in pages" 
        :key="page.num" 
        :id="`page-${page.num}`" 
        class="pdf-page-canvas"
      ></canvas>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import pdfjs from 'pdfjs-dist';
import 'pdfjs-dist/build/pdf.worker.entry'; // 引入worker

const props = defineProps({
  src: {
    type: String,
    required: true
  }
});

const pages = ref([]);        // 存储PDF所有页的信息
const flattenedToc = ref([]); // 扁平化的目录列表

// 初始化PDF查看器
const initPDFViewer = async () => {
  try {
    // 加载PDF文档
    const loadingTask = pdfjs.getDocument(props.src);
    const pdf = await loadingTask.promise;

    // 提取目录(大纲)
    const outline = await pdf.getOutline();
    flattenedToc.value = flattenOutline(outline);

    // 加载所有页并渲染
    const totalPages = pdf.numPages;
    for (let i = 1; i <= totalPages; i++) {
      const page = await pdf.getPage(i);
      renderPage(page, i);
    }
  } catch (error) {
    console.error('PDF加载失败:', error);
  }
};

// 扁平化目录结构(处理嵌套目录)
const flattenOutline = (outline, parentTitle = '', level = 0) => {
  const result = [];
  outline.forEach((item, index) => {
    const title = `${'  '.repeat(level)}${item.title}`;
    result.push({
      id: `${parentTitle}-${index}`,
      title,
      dest: item.dest
    });
    if (item.items) {
      result.push(...flattenOutline(item.items, item.title, level + 1));
    }
  });
  return result;
};

// 渲染单页PDF到Canvas
const renderPage = (page, pageNum) => {
  const canvas = document.getElementById(`page-${pageNum}`);
  const context = canvas.getContext('2d');
  const viewport = page.getViewport({ scale: 1.5 }); // 缩放比例,可调整

  canvas.width = viewport.width;
  canvas.height = viewport.height;

  const renderContext = {
    canvasContext: context,
    viewport
  };
  page.render(renderContext);
};

// 目录跳转(平滑滚动到对应页面)
const scrollToPage = (dest) => {
  const pageNum = Array.isArray(dest) ? dest[0].num : dest;
  const pageElement = document.getElementById(`page-${pageNum}`);
  pageElement?.scrollIntoView({ behavior: 'smooth' });
};

onMounted(() => {
  initPDFViewer();
});
</script>

<style scoped>
.pdf-viewer-container {
  display: flex;
  height: 100vh;
}

.toc-column {
  width: 300px;
  border-right: 1px solid #ccc;
  overflow-y: auto;
  padding: 20px;
}

.toc-list {
  list-style: none;
  padding: 0;
}

.toc-item {
  padding: 8px 12px;
  cursor: pointer;
  transition: background 0.3s;
}

.toc-item:hover {
  background: #f5f5f5;
}

.pdf-viewer {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
}

.pdf-page-canvas {
  display: block;
  margin: 0 auto 20px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
</style>

三、使用示例

在父组件中引入 PDFViewer 并传入 PDF 地址:

javascript 复制代码
<template>
  <div>
    <PDFViewer src="/static/report.pdf" />
  </div>
</template>

<script setup>
import PDFViewer from './components/PDFViewer.vue';
</script>

四、功能说明

  1. 目录提取与渲染 :通过 pdf.getOutline() 提取 PDF 内置的目录(大纲),并递归处理嵌套结构,生成扁平化的目录列表。
  2. PDF 页面渲染 :使用 canvas 逐页渲染 PDF 内容,支持缩放和自适应布局。
  3. 目录跳转 :点击目录项时,通过 scrollIntoView 平滑滚动到对应页面。

五、Vue2 兼容方案

若使用 Vue2,可将上述代码调整为选项式 API 风格,并确保 pdfjs-dist 版本兼容(如 pdfjs-dist@2.16.105)。核心逻辑与 Vue3 一致,仅语法略有差异。

通过以上步骤,即可在 Vue 项目中实现 "左侧目录 + 右侧 PDF 预览" 的完整功能,满足文档查阅、目录导航的需求。

相关推荐
GIS阵地1 天前
QgsProviderMetadata 详解(基于 QGIS 3.40.13 API)
数据库·qt·arcgis·oracle·gis·开源软件·qgis
城数派2 天前
2000-2024年1km精度人口分布栅格数据(全球/全国/分省/分市)
arcgis·信息可视化·数据分析·excel
城数派2 天前
1984-2024年中国10米分辨率城市土地利用栅格数据(商业、公服、居住等9类)
arcgis·信息可视化·数据分析·excel
城数派2 天前
2015-2024年我国1km分辨率逐日地表温度(LST)栅格数据
数据库·arcgis·信息可视化·数据分析·excel
城数派2 天前
中国全国土壤有机碳密度数据集(2010-2024年)
数据库·arcgis·信息可视化·数据分析·excel
Ama_tor2 天前
Electron经典入门 |创建“Hello World”桌面应用,并将其打包成 Windows 可执行文件(.exe)
arcgis
551只玄猫3 天前
【海洋空间信息工程概论 实验报告2】海洋空间数据管理
arcgis·课程设计·实验报告·海洋·地理·海洋空间工程
薛定猫AI4 天前
【一键配置】优雅使用Claude Code:从安装到上手的完整教程
人工智能·arcgis·编辑器·vim
NULIWEIMENXIANG4 天前
ArcPy 程序调用 QGIS 进程实现几何拓扑检查
python·arcgis·gis
三*一5 天前
基于 Turf.js 实现高精度多边形修整工具(模拟 ArcGIS 修整功能)
开发语言·前端·javascript·arcgis·maobox gl·turf.js