vue3+ts+pdfjs-dist查看pdf

"pdfjs-dist": "^4.1.392",

"lodash-es": "^4.17.21",

"vite-plugin-top-level-await": "^1.4.1",

"vue": "^3.4.15",

TypeScript 复制代码
<template>
	<div class="pdf-container">
		<canvas :id="`pdf-canvas`" />
	</div>
	<div class="page-tool">
		<div class="page-tool-item" @click="lastPage">上一页</div>
		<div class="page-tool-item" @click="nextPage">下一页</div>
		<div class="page-tool-item">{{state.pageNum}}/{{state.numPages}}</div>
		<div class="page-tool-item" @click="pageZoomOut">放大</div>
		<div class="page-tool-item" @click="pageZoomIn">缩小</div>
	</div>
</template>

<script lang="ts" setup>

	import * as PDFJS from 'pdfjs-dist'
	import * as PdfWorker from 'pdfjs-dist/build/pdf.worker.mjs'
	import { nextTick, ref, Ref, watch, reactive, computed } from 'vue'
	import { isEmpty, debounce } from 'lodash-es'
	(window as any).PdfWorker = PdfWorker


	const props : any = defineProps({
		pdf: {
			required: true
		}
	})

	const state = reactive({
		source: "", //预览pdf文件地址
		pageNum: 1, //当前页面
		scale: 1, // 缩放比例
		numPages: 0, // 总页数
		showpdf: true,
	});

	const scaleFun = computed(() => 'transform:scale(${state.scale})')

	let pdfDoc : any = null
	const pdfPages : Ref = ref(0)
	const pdfScale : Ref = ref(1.3)
	const loadFile = async (url : any) => {
		// 设定pdfjs的 workerSrc 参数
		// PDFJS.GlobalWorkerOptions.workerSrc = PdfWorker
		const loadingTask = PDFJS.getDocument(url)
		loadingTask.promise.then(async (pdf : any) => {
			pdfDoc = pdf // 保存加载的pdf文件流
			state.numPages = pdfPages.value = pdfDoc.numPages // 获取pdf文件的总页数
			await nextTick(() => {
				renderPage(1) // 将pdf文件内容渲染到canvas
			})
		}).catch((error : any) => {
			//可以用自己组件库弹出提示框
			console.log(error)
		})
	}

	const renderPage = (num : any) => {
		pdfDoc.getPage(num).then((page : any) => {
			page.cleanup()
			const canvas : any = document.getElementById(`pdf-canvas`)
			if (canvas) {
				const ctx = canvas.getContext('2d')
				const dpr = window.devicePixelRatio || 1
				const bsr = ctx.webkitBackingStorePixelRatio ||
					ctx.mozBackingStorePixelRatio ||
					ctx.msBackingStorePixelRatio ||
					ctx.oBackingStorePixelRatio ||
					ctx.backingStorePixelRatio ||
					1
				const ratio = dpr / bsr
				const viewport = page.getViewport({ scale: pdfScale.value })
				canvas.width = viewport.width * ratio
				canvas.height = viewport.height * ratio
				canvas.style.width = viewport.width + 'px'
				canvas.style.height = viewport.height + 'px'
				ctx.setTransform(ratio, 0, 0, ratio, 0, 0)
				const renderContext = {
					canvasContext: ctx,
					viewport: viewport
				}
				page.render(renderContext)
				state.pageNum = num;
				// if (num < pdfPages.value) {
				//   renderPage(num + 1)
				// }
			}
		})
	}
	function lastPage() {
		if (state.pageNum > 1) {
			renderPage(state.pageNum - 1);
		}
	}
	function nextPage() {
		if (state.pageNum < state.numPages) {
			renderPage(state.pageNum + 1);
		}
	}
	function pageZoomOut() {
		if (pdfScale.value < 5) {
			pdfScale.value += 0.1;
			renderPage(state.pageNum);
		}
	}
	function pageZoomIn() {
		if (pdfScale.value > 0.5) {
			pdfScale.value -= 0.1;
			renderPage(state.pageNum);
		}
	}

	const debouncedLoadFile = debounce((pdf : any) => loadFile(pdf), 1000)
	watch(() => props.pdf, (newValue : any) => {
		!isEmpty(newValue) && debouncedLoadFile(newValue)
	}, {
		immediate: true
	})
</script>

<style scoped>
	.page-tool {
		position: absolute;
		bottom: 35px;
		padding-left: 15px;
		padding-right: 15px;
		display: flex;
		align-items: center;
		background: rgb(66, 66, 66);
		color: white;
		border-radius: 19px;
		z-index: 100;
		cursor: pointer;
		margin-left: 50%;
		transform: translateX(-50%);
	}

	.page-tool-item {
		padding: 8px 15px;
		padding-left: 10px;
		cursor: pointer;
	}

	.pdf-container {
		width: 1000px;
		height: 600px;
		resize: both;
		overflow: auto;
		/* 启用滚动条 */
	}

	canvas {
		width: 100%;
		pointer-events: none;
		max-height: 100vh;
		/* 设置最大高度为视口高度 */
	}
</style>

效果:

相关推荐
kisshyshy1 分钟前
前端存储、表单异步提交与 this 指向完全指南
前端·javascript·html
cidy_982 分钟前
Skills 技能库- JulyCode
前端
Csvn6 分钟前
TypeScript 泛型约束的 3 层演进:从 `extends` 到条件类型到重载推导
前端
小四的小六7 分钟前
AI产品翻车实录:模型总结幻觉的三大类型与检测方案
前端·openai·ai编程
狂师8 分钟前
端开发必装 Skill 清单:6 款 AI 技能,让你的开发效率原地起飞
前端·程序员·开源
3630458419 分钟前
KlineChartQuant Tooltip 高频交互 200FPS 性能优化完整复盘
前端·架构
嘉泰姆半导体官方13 分钟前
CXAR41337C 双通道数字音频功放 | 2×20W | EQ+DRC | I²S | MCLK-Less - 嘉泰姆电子
前端·javascript·数据库
PedroQue9915 分钟前
uni-router v2.0.0:四大功能拆分为插件,按需加载
前端·uni-app
Lazy_zheng17 分钟前
TDD 实战:Claude Code Superpowers 保姆级教程14 个 Skills 全解析 + 实战开发
前端·claude·vibecoding
胡萝卜术17 分钟前
从逐一合并到多路归并:力扣23「合并K个升序链表」的三种解法进化之路
前端·javascript·面试