vue3: pdf.js 3.4.120 using javascript

bash 复制代码
npm install [email protected]

项目结构:

pdfjsViewer.vue

javascript 复制代码
<template>
  <div>
      <div v-if="loading" class="flex justify-center items-center py-8">
          <div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500"></div>
      </div>
      <div v-else>
          <div class="flex flex-col md:flex-row gap-4 mb-4">
              <button @click="loadPreviousPage" :disabled="currentPage === 1" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
                  <i class="fa fa-arrow-left mr-1"></i> 上一页
              </button>
              <button @click="loadFirstPage" :disabled="currentPage === 1" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
                  <i class="fa fa-fast-backward mr-1"></i> 第一页
              </button>
              <span class="text-lg self-center">
                  第 {{ currentPage }} 页,共 {{ totalPages }} 页
              </span>
              <button @click="loadNextPage" :disabled="currentPage === totalPages" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
                  下一页 <i class="fa fa-arrow-right ml-1"></i>
              </button>
              <button @click="loadLastPage" :disabled="currentPage === totalPages" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
                  最后一页 <i class="fa fa-fast-forward ml-1"></i>
              </button>
          </div>
      </div>
      <div class="flex items-center mb-4">
          <span class="mr-2">缩放:</span>
          <button @click="zoomOut" class="px-2 py-1 bg-gray-200 rounded hover:bg-gray-300">
              <i class="fa fa-search-minus"></i>
          </button>
          <span class="mx-2">{{ Math.round(scale * 100) }}%</span>
          <button @click="zoomIn" class="px-2 py-1 bg-gray-200 rounded hover:bg-gray-300">
              <i class="fa fa-search-plus"></i>
          </button>
          <select v-model="scaleValue" @change="changeScale" class="ml-4 px-2 py-1 border rounded">
              <option value="0.5">50%</option>
              <option value="0.75">75%</option>
              <option value="1">100%</option>
              <option value="1.25">125%</option>
              <option value="1.5">150%</option>
              <option value="2">200%</option>
          </select>
      </div>  
      <div class="relative w-full bg-gray-100" ref="pdfContainer">
          <canvas ref="pdfCanvas" class="border-2 border-gray-300 rounded shadow-lg w-full"></canvas>
      </div>
  </div>
</template>
 
<script>
// 调整导入路径以适应3.4.120版本
import * as pdfjsLib from 'pdfjs-dist/build/pdf';
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker';
 
// 设置worker路径
pdfjsLib.GlobalWorkerOptions.workerSrc = '/node_modules/pdfjs-dist/build/pdf.worker.js';
 
export default {
  name: 'PdfViewer',
  props: {
      pdfPath: {
          type: [String, Uint8Array],
          required: true
      }
  },
  data() {
      return {
          //pdfDoc: null,
          currentPage: 1,
          totalPages: 0,
          scale: 1,
          scaleValue: '1',
          canvas: null,
          ctx: null,
          renderTask: null,
          loading: true,
          error: null
      };
  },
  watch: {
      pdfPath: {
          immediate: true,
          handler(newVal) {
              this.loadPDF(newVal);
          }
      }
  },
  mounted() {
      this.$nextTick(() => {
          this.canvas = this.$refs.pdfCanvas;
          this.ctx = this.canvas.getContext('2d');
      });
  },
  methods: {
      async loadPDF(path) {
          this.loading = true;
          this.error = null;
          this.pdfDoc= null;
 
          try {
              await this.$nextTick();
               
              if (!this.$refs.pdfCanvas) {
                  console.error('Canvas元素未找到');
                  this.error = 'Canvas元素未找到';
                  return;
              }
               
              this.canvas = this.$refs.pdfCanvas;
              this.ctx = this.canvas.getContext('2d');
               
              if (this.renderTask) {
                  //this.renderTask.cancel();
              }
 
              this.currentPage = 1;
 
              const loadingTask = pdfjsLib.getDocument({
                  url: path,
                  disableFontFace: false,
                  cMapUrl: '/node_modules/pdfjs-dist/cmaps/',
                  cMapPacked: true
              });
 
              this.pdfDoc = await loadingTask.promise;
              this.totalPages = this.pdfDoc.numPages;
               
              console.log('PDF加载成功,总页数:', this.totalPages);
              await this.renderPage(this.currentPage);
               
              this.$emit('pageChanged', this.currentPage, this.totalPages);
          } catch (error) {
              console.error('加载PDF时出错:', error);
              this.error = error.message;
              alert('加载PDF失败: ' + error.message);
          } finally {
              this.loading = false;
          }
      },
 
      async renderPage(num) {
          if (!this.pdfDoc || !this.canvas || !this.ctx) {
              console.error('PDF文档或Canvas未初始化');
              return;
          }
 
          try {
 
              await this.$nextTick();
              console.log("renderPage:");
              console.log(this.pdfDoc);
              console.log('渲染第', num, '页,缩放比例:', this.scale);
               
              if (this.renderTask) {
                  //this.renderTask.cancel();
              }
 
              const page = await this.pdfDoc.getPage(num);
               console.log("pp",page);
              const viewport = page.getViewport({ scale: this.scale });
               
              // 设置canvas尺寸
              this.canvas.height = viewport.height;
              this.canvas.width = viewport.width;
               
              // 清除canvas
              this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
 
              console.log('Canvas尺寸设置为:', this.canvas.width, 'x', this.canvas.height);
 
              const renderContext = {
                  canvasContext: this.ctx,
                  viewport: viewport
              };
 
              console.log('开始渲染页面...');
              this.renderTask = page.render(renderContext);
 
              await this.renderTask.promise;
 
              console.log('页面渲染成功');
 
              this.$emit('pageChanged', num, this.totalPages);
          } catch (error) {
              if (error.name !== 'RenderingCancelledException') {
                  console.error('渲染页面时出错:', error);
                  this.error = error.message;
              }
          }
      },
      async loadFirstPage() {
          if (this.currentPage !== 1) {
              this.currentPage = 1;
              console.log("Page:");
              console.log(this.pdfDoc);
              await this.renderPage(this.currentPage);
          }
      },
      async loadPreviousPage() {
          if (this.currentPage > 1) {
              this.currentPage--;
              console.log("Page:");
              console.log(this.pdfDoc);
              await this.renderPage(this.currentPage);
          }
      },
      async loadNextPage() {
          if (this.currentPage < this.totalPages) {
              this.currentPage++;
              console.log("Page:");
              console.log(this.pdfDoc);
              await this.renderPage(this.currentPage);
          }
      },
      async loadLastPage() {
          if (this.currentPage !== this.totalPages) {
              this.currentPage = this.totalPages;
              console.log("Page:");
              console.log(this.pdfDoc);
              await this.renderPage(this.currentPage);
          }
      },
      zoomIn() {
          this.scale += 0.25;
          this.scaleValue = this.scale.toString();
          this.renderPage(this.currentPage);
      },
      zoomOut() {
          if (this.scale > 0.5) {
              this.scale -= 0.25;
              this.scaleValue = this.scale.toString();
              this.renderPage(this.currentPage);
          }
      },
      changeScale() {
          this.scale = parseFloat(this.scaleValue);
          this.renderPage(this.currentPage);
      }
  }
};
</script>
 
<style scoped>
.pdf-container {
  overflow: auto;
  min-height: 500px;
}
canvas {
  max-width: 100%;
  display: block;
}
button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
</style>

dupdf.vue

javascript 复制代码
<!--
 * ......................................&&.........................
 * ....................................&&&..........................
 * .................................&&&&............................
 * ...............................&&&&..............................
 * .............................&&&&&&..............................
 * ...........................&&&&&&....&&&..&&&&&&&&&&&&&&&........
 * ..................&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&..............
 * ................&...&&&&&&&&&&&&&&&&&&&&&&&&&&&&.................
 * .......................&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&.........
 * ...................&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&...............
 * ..................&&&   &&&&&&&&&&&&&&&&&&&&&&&&&&&&&............
 * ...............&&&&&@  &&&&&&&&&&..&&&&&&&&&&&&&&&&&&&...........
 * ..............&&&&&&&&&&&&&&&.&&....&&&&&&&&&&&&&..&&&&&.........
 * ..........&&&&&&&&&&&&&&&&&&...&.....&&&&&&&&&&&&&...&&&&........
 * ........&&&&&&&&&&&&&&&&&&&.........&&&&&&&&&&&&&&&....&&&.......
 * .......&&&&&&&&.....................&&&&&&&&&&&&&&&&.....&&......
 * ........&&&&&.....................&&&&&&&&&&&&&&&&&&.............
 * ..........&...................&&&&&&&&&&&&&&&&&&&&&&&............
 * ................&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&............
 * ..................&&&&&&&&&&&&&&&&&&&&&&&&&&&&..&&&&&............
 * ..............&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....&&&&&............
 * ...........&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&......&&&&............
 * .........&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&.........&&&&............
 * .......&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&...........&&&&............
 * ......&&&&&&&&&&&&&&&&&&&...&&&&&&...............&&&.............
 * .....&&&&&&&&&&&&&&&&............................&&..............
 * ....&&&&&&&&&&&&&&&.................&&...........................
 * ...&&&&&&&&&&&&&&&.....................&&&&......................
 * ...&&&&&&&&&&.&&&........................&&&&&...................
 * ..&&&&&&&&&&&..&&..........................&&&&&&&...............
 * ..&&&&&&&&&&&&...&............&&&.....&&&&...&&&&&&&.............
 * ..&&&&&&&&&&&&&.................&&&.....&&&&&&&&&&&&&&...........
 * ..&&&&&&&&&&&&&&&&..............&&&&&&&&&&&&&&&&&&&&&&&&.........
 * ..&&.&&&&&&&&&&&&&&&&&.........&&&&&&&&&&&&&&&&&&&&&&&&&&&.......
 * ...&&..&&&&&&&&&&&&.........&&&&&&&&&&&&&&&&...&&&&&&&&&&&&......
 * ....&..&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&...........&&&&&&&&.....
 * .......&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&..............&&&&&&&....
 * .......&&&&&.&&&&&&&&&&&&&&&&&&..&&&&&&&&...&..........&&&&&&....
 * ........&&&.....&&&&&&&&&&&&&.....&&&&&&&&&&...........&..&&&&...
 * .......&&&........&&&.&&&&&&&&&.....&&&&&.................&&&&...
 * .......&&&...............&&&&&&&.......&&&&&&&&............&&&...
 * ........&&...................&&&&&&.........................&&&..
 * .........&.....................&&&&........................&&....
 * ...............................&&&.......................&&......
 * ................................&&......................&&.......
 * .................................&&..............................
 * ..................................&..............................
 *
 * @Author: geovindu
 * @Date: 2025-05-12 19:12:10
 * @LastEditors: geovindu
 * @LastEditTime: 2025-05-12 19:17:45
 * @FilePath: \vue\vuejs\src\components\dupdf.vue
 * @Description: geovindu
 * @lib,packpage:
 *
 * @IDE: vscode
 * @jslib: node 20 vue.js 3.0
 * @OS: windows10
 * @database: mysql 8.0  sql server 2019 postgreSQL 16
 * Copyright (c) geovindu 2025 by [email protected], All Rights Reserved.
 -->
 
<template>
  <div class="container mx-auto p-4">
      <h1 class="text-2xl font-bold mb-4">PDF查看器</h1>
      <PdfViewer :pdfPath="pdfPath" @pageChanged="handlePageChanged" />
      <div class="mt-4">
          <input type="file" @change="handleFileSelect" accept=".pdf" class="border p-2 rounded">
      </div>
  </div>
</template>
 
<script>
import PdfViewer from './pdfjsViewer.vue';
 
export default {
  name: 'App',
  components: {
      PdfViewer
  },
  data() {
      return {
          pdfPath: './09.pdf'
      };
  },
  methods: {
      handlePageChanged(currentPage, totalPages) {
          console.log(`当前页码: ${currentPage}, 总页数: ${totalPages}`);
          // 可以在这里更新父组件状态或执行其他操作
      },
      async handleFileSelect(e) {
          const file = e.target.files[0];
          if (file) {
              const blob = new Blob([file], { type: file.type });
              this.pdfPath = URL.createObjectURL(blob);
          }
      }
  }
};
</script>

App.vue

javascript 复制代码
<!--
 *
 *   ┏┓   ┏┓+ +
 *  ┏┛┻━━━┛┻┓ + +
 *  ┃       ┃  
 *  ┃   ━   ┃ ++ + + +
 *  ████━████ ┃+
 *  ┃       ┃ +
 *  ┃   ┻   ┃
 *  ┃       ┃ + +
 *  ┗━┓   ┏━┛
 *    ┃   ┃           
 *    ┃   ┃ + + + +
 *    ┃   ┃
 *    ┃   ┃ +  神兽保佑
 *    ┃   ┃    代码无bug  
 *    ┃   ┃  +         
 *    ┃    ┗━━━┓ + +
 *    ┃        ┣┓
 *    ┃        ┏┛
 *    ┗┓┓┏━┳┓┏┛ + + + +
 *     ┃┫┫ ┃┫┫
 *     ┗┻┛ ┗┻┛+ + + +
 *
 *
 * @Author: geovindu
 * @Date: 2024-08-05 08:57:12
 * @LastEditors: geovindu
 * @LastEditTime: 2024-10-16 09:20:45
 * @FilePath: \vue\vuejs\src\App.vue
 * @Description: geovindu
 * @lib,packpage:
 *
 * @IDE: vscode
 * @jslib: node 20 vue.js 3.0
 * @OS: windows10
 * @database: mysql 8.0  sql server 2019 postgreSQL 16
 * Copyright (c) geovindu 2024 by [email protected], All Rights Reserved.
 -->
 
<script setup>
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from './components/HelloWorld.vue'
</script>
 
<template>
  <header>
    <img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
 
    <div class="wrapper">
      <HelloWorld msg="You did it!" />
 
      <nav>
        <RouterLink to="/">Home</RouterLink>
        <RouterLink to="/about">About</RouterLink>
        <RouterLink to="/doc">Word</RouterLink>
        <RouterLink to="/excel">Excel</RouterLink>
        <RouterLink to="/pdf">Pdf</RouterLink>
        <RouterLink to="/pdfjs">Pdfjs</RouterLink>
        <RouterLink to="/dupdfjs">duPdfjs</RouterLink>
      </nav>
    </div>
  </header>
 
  <RouterView />
</template>
 
<style scoped>
header {
  line-height: 1.5;
  max-height: 100vh;
}
 
.logo {
  display: block;
  margin: 0 auto 2rem;
}
 
nav {
  width: 100%;
  font-size: 12px;
  text-align: center;
  margin-top: 2rem;
}
 
nav a.router-link-exact-active {
  color: var(--color-text);
}
 
nav a.router-link-exact-active:hover {
  background-color: transparent;
}
 
nav a {
  display: inline-block;
  padding: 0 1rem;
  border-left: 1px solid var(--color-border);
}
 
nav a:first-of-type {
  border: 0;
}
 
@media (min-width: 1024px) {
  header {
    display: flex;
    place-items: center;
    padding-right: calc(var(--section-gap) / 2);
  }
 
  .logo {
    margin: 0 2rem 0 0;
  }
 
  header .wrapper {
    display: flex;
    place-items: flex-start;
    flex-wrap: wrap;
  }
 
  nav {
    text-align: left;
    margin-left: -1rem;
    font-size: 1rem;
 
    padding: 1rem 0;
    margin-top: 1rem;
  }
}
</style>

word,excel,ppt 在线预览暂不示例

相关推荐
Python猫14 分钟前
付费专栏·Python潮流周刊电子书合集(epub、pdf、markdown)下载
python·计算机·pdf·电子书·资料
q5673152317 分钟前
Go语言多线程爬虫与代理IP反爬
开发语言·爬虫·tcp/ip·golang
Chandler2419 分钟前
Go语言即时通讯系统 开发日志day1
开发语言·后端·golang
懒羊羊我小弟1 小时前
使用 ECharts GL 实现交互式 3D 饼图:技术解析与实践
前端·vue.js·3d·前端框架·echarts
强化学习与机器人控制仿真1 小时前
openpi 入门教程
开发语言·人工智能·python·深度学习·神经网络·机器人·自动驾驶
运维@小兵1 小时前
vue访问后端接口,实现用户注册
前端·javascript·vue.js
雨汨1 小时前
web:InfiniteScroll 无限滚动
前端·javascript·vue.js
小盐巴小严1 小时前
正则表达式
javascript·正则表达式
明月看潮生1 小时前
青少年编程与数学 02-019 Rust 编程基础 08课题、字面量、运算符和表达式
开发语言·青少年编程·rust·编程与数学
JackieZhengChina2 小时前
用python清除PDF文件中的水印(Adobe Acrobat 无法删除)
pdf