当前位置: 首页 > news >正文

vue3: pdf.js 3.4.120 using javascript

npm install pdfjs-dist@3.4.120

 项目结构:

pdfjsViewer.vue

<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;// 清除canvasthis.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

<!--* ......................................&&.........................* ....................................&&&..........................* .................................&&&&............................* ...............................&&&&..............................* .............................&&&&&&..............................* ...........................&&&&&&....&&&..&&&&&&&&&&&&&&&........* ..................&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&..............* ................&...&&&&&&&&&&&&&&&&&&&&&&&&&&&&.................* .......................&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&.........* ...................&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&...............* ..................&&&   &&&&&&&&&&&&&&&&&&&&&&&&&&&&&............* ...............&&&&&@  &&&&&&&&&&..&&&&&&&&&&&&&&&&&&&...........* ..............&&&&&&&&&&&&&&&.&&....&&&&&&&&&&&&&..&&&&&.........* ..........&&&&&&&&&&&&&&&&&&...&.....&&&&&&&&&&&&&...&&&&........* ........&&&&&&&&&&&&&&&&&&&.........&&&&&&&&&&&&&&&....&&&.......* .......&&&&&&&&.....................&&&&&&&&&&&&&&&&.....&&......* ........&&&&&.....................&&&&&&&&&&&&&&&&&&.............* ..........&...................&&&&&&&&&&&&&&&&&&&&&&&............* ................&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&............* ..................&&&&&&&&&&&&&&&&&&&&&&&&&&&&..&&&&&............* ..............&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&....&&&&&............* ...........&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&......&&&&............* .........&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&.........&&&&............* .......&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&...........&&&&............* ......&&&&&&&&&&&&&&&&&&&...&&&&&&...............&&&.............* .....&&&&&&&&&&&&&&&&............................&&..............* ....&&&&&&&&&&&&&&&.................&&...........................* ...&&&&&&&&&&&&&&&.....................&&&&......................* ...&&&&&&&&&&.&&&........................&&&&&...................* ..&&&&&&&&&&&..&&..........................&&&&&&&...............* ..&&&&&&&&&&&&...&............&&&.....&&&&...&&&&&&&.............* ..&&&&&&&&&&&&&.................&&&.....&&&&&&&&&&&&&&...........* ..&&&&&&&&&&&&&&&&..............&&&&&&&&&&&&&&&&&&&&&&&&.........* ..&&.&&&&&&&&&&&&&&&&&.........&&&&&&&&&&&&&&&&&&&&&&&&&&&.......* ...&&..&&&&&&&&&&&&.........&&&&&&&&&&&&&&&&...&&&&&&&&&&&&......* ....&..&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&...........&&&&&&&&.....* .......&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&..............&&&&&&&....* .......&&&&&.&&&&&&&&&&&&&&&&&&..&&&&&&&&...&..........&&&&&&....* ........&&&.....&&&&&&&&&&&&&.....&&&&&&&&&&...........&..&&&&...* .......&&&........&&&.&&&&&&&&&.....&&&&&.................&&&&...* .......&&&...............&&&&&&&.......&&&&&&&&............&&&...* ........&&...................&&&&&&.........................&&&..* .........&.....................&&&&........................&&....* ...............................&&&.......................&&......* ................................&&......................&&.......* .................................&&..............................* ..................................&..............................** @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 geovindu@163.com, 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

<!--**   ┏┓   ┏┓+ +*  ┏┛┻━━━┛┻┓ + +*  ┃       ┃  *  ┃   ━   ┃ ++ + + +*  ████━████ ┃+*  ┃       ┃ +*  ┃   ┻   ┃*  ┃       ┃ + +*  ┗━┓   ┏━┛*    ┃   ┃           *    ┃   ┃ + + + +*    ┃   ┃*    ┃   ┃ +  神兽保佑*    ┃   ┃    代码无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 geovindu@163.com, 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 在线预览暂不示例

相关文章:

  • LeetCode 513 找树左下角的值 LeetCode 112 路径总和 LeetCode106 从中序与后序遍历序列构造二叉树
  • 单片机-STM32部分:13-1、蜂鸣器
  • AI与IoT携手,精准农业未来已来
  • 接口自动化测试设计思路--设计实战
  • 【信息安全相关基础篇:了解签名与验签是什么及用途】
  • 蓝桥杯13届 卡牌
  • Dapp开发-如何开发一个dapp
  • Transformer——Q74 推导动态FFN(Dynamic FFN)的门控权重更新公式
  • 【内蒙古】《内蒙古自治区本级政务信息化建设项目预算支出标准(试行)》(内财预〔2024〕1449号)-费用标准解读系列
  • 计算机图形学编程(使用OpenGL和C++)(第2版)学习笔记 09.天空和背景
  • 交叉类型的属性合并规则
  • 数组作为指针计算大小时的误区
  • 扩展:React 项目执行 yarn eject 后的 config 目录结构详解
  • Kotlin 内联函数(Inline Functions):性能优化与实战指南
  • CSS3 遮罩
  • 嵌入式Linux I2C驱动开发详解
  • 架构、构架、结构、框架之间有什么区别?|系统设计|系统建模
  • Golang 应用的 CI/CD 与 K8S 自动化部署全流程指南
  • TCPIP详解 卷1协议 九 广播和本地组播(IGMP 和 MLD)
  • geoserver发布arcgis瓦片地图服务(最新版本)
  • 小米SU7 Ultra风波升级:数百名车主要求退车,车主喊话雷军“保持真诚”
  • 济南市委副秘书长吕英伟已任历下区领导
  • 商务部召开外贸企业圆桌会:全力为外贸企业纾困解难,提供更多支持
  • 男子退机票被收90%的手续费,律师:虽然合规,但显失公平
  • 新华时评:中美经贸会谈为全球经济纾压增信
  • 波兰关闭俄罗斯驻克拉科夫领事馆