vite:npm 安装 pdfjs-dist , PDF.js View 示例

pdfjs-dist 是 Mozilla 的 PDF.js 库的预构建版本,能让你在项目里展示 PDF 文件。下面为你介绍如何用 npm 安装 pdfjs-dist 并应用 pdf.js 和 pdf.worker.js

为了方便,我将使用 vite 搭建一个原生 js 项目。

1.创建项目
npm create vite@latest pdf-view
选:Vanilla
选:JavaScript

2.初始化项目
 cd pdf-view
 cnpm install

3.安装 pdfjs-dist
 cnpm install pdfjs-dist@3.11.174 --save

编写 index1.html  如下

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>PDF.js View 示例</title><link rel="stylesheet" href="/pdf.css" />
</head>
<body><div class="container"><input type="file" id="fileInput" accept=".pdf"><div class="controls"><button id="prevPage">← 上一页</button><div class="page-control"><input type="number" id="pageInput" min="1" step="1" disabled><button id="goButton" disabled>跳转</button><span>/ <span id="totalPages">-</span></span></div><button id="nextPage">下一页 →</button><div class="scale-control"><button id="zoomOut">-</button><span id="scaleValue">100%</span><button id="zoomIn">+</button></div></div><div id="canvasContainer"><canvas id="pdfCanvas"></canvas></div></div><script type="module" src="/pdf-view.js"></script>
</body>
</html>

 编写 pdf.css  如下

    .container {max-width: 1000px;margin: 10px auto;padding: 15px;}.controls {display: flex;gap: 10px;align-items: center;margin-bottom: 15px;}#canvasContainer {border: 1px solid #ddd;overflow: auto;max-height: 80vh;position: relative;}canvas {transition: transform 0.2s ease;}input[type="number"] {width: 60px;padding: 4px;text-align: center;}button {padding: 6px 12px;background: #007bff;color: white;border: none;border-radius: 4px;cursor: pointer;}button:disabled {background: #6c757d;cursor: not-allowed;}.scale-control {margin-left: auto;display: flex;align-items: center;gap: 5px;}

编写 pdf-view.js  如下

import * as pdfjsLib from 'pdfjs-dist';
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.min.js';// 初始化配置
pdfjsLib.GlobalWorkerOptions.workerSrc = pdfjsWorker;// 状态管理对象
const state = {currentPage: 1,totalPages: 0,scale: 1.0,pdfDoc: null,isRendering: false,MIN_SCALE: 0.5,MAX_SCALE: 3.0,ZOOM_STEP: 0.1
};// DOM 元素引用
const dom = {canvas: document.getElementById('pdfCanvas'),container: document.getElementById('canvasContainer'),prevBtn: document.getElementById('prevPage'),nextBtn: document.getElementById('nextPage'),pageInput: document.getElementById('pageInput'),goBtn: document.getElementById('goButton'),totalPages: document.getElementById('totalPages'),zoomIn: document.getElementById('zoomIn'),zoomOut: document.getElementById('zoomOut'),scaleValue: document.getElementById('scaleValue'),fileInput: document.getElementById('fileInput')
};// 初始化事件监听
function initEventListeners() {// 文件选择dom.fileInput.addEventListener('change', handleFileSelect);// 翻页控制dom.prevBtn.addEventListener('click', () => changePage(-1));dom.nextBtn.addEventListener('click', () => changePage(1));// 页面跳转dom.goBtn.addEventListener('click', handlePageJump);dom.pageInput.addEventListener('keypress', e => {if (e.key === 'Enter') handlePageJump();});// 缩放控制dom.zoomIn.addEventListener('click', () => changeScale(state.ZOOM_STEP));dom.zoomOut.addEventListener('click', () => changeScale(-state.ZOOM_STEP));// 鼠标滚轮缩放dom.container.addEventListener('wheel', handleWheelZoom, { passive: false });
}// 处理文件选择
async function handleFileSelect(e) {const file = e.target.files[0];if (!file) return;try {const arrayBuffer = await file.arrayBuffer();state.pdfDoc = await pdfjsLib.getDocument(arrayBuffer).promise;state.totalPages = state.pdfDoc.numPages;initUI();await renderPage();} catch (err) {console.error('文件加载失败:', err);}
}// 初始化界面状态
function initUI() {dom.totalPages.textContent = state.totalPages;dom.pageInput.max = state.totalPages;dom.pageInput.value = 1;dom.pageInput.disabled = false;dom.goBtn.disabled = false;dom.zoomIn.disabled = false;dom.zoomOut.disabled = false;
}// 核心渲染函数
async function renderPage() {if (!state.pdfDoc || state.isRendering) return;state.isRendering = true;try {const page = await state.pdfDoc.getPage(state.currentPage);const viewport = page.getViewport({ scale: state.scale });// 调整画布尺寸dom.canvas.width = viewport.width;dom.canvas.height = viewport.height;// 渲染页面await page.render({canvasContext: dom.canvas.getContext('2d'),viewport: viewport}).promise;updateUIState();} catch (err) {console.error('页面渲染失败:', err);} finally {state.isRendering = false;}
}// 更新界面状态
function updateUIState() {dom.pageInput.value = state.currentPage;dom.totalPages.textContent = state.totalPages;dom.scaleValue.textContent = `${Math.round(state.scale * 100)}%`;// 按钮状态dom.prevBtn.disabled = state.currentPage <= 1;dom.nextBtn.disabled = state.currentPage >= state.totalPages;dom.zoomIn.disabled = state.scale >= state.MAX_SCALE;dom.zoomOut.disabled = state.scale <= state.MIN_SCALE;
}// 翻页处理
function changePage(offset) {const newPage = state.currentPage + offset;if (newPage < 1 || newPage > state.totalPages) return;state.currentPage = newPage;renderPage();
}// 页面跳转处理
function handlePageJump() {const target = parseInt(dom.pageInput.value) || 1;const validPage = Math.max(1, Math.min(target, state.totalPages));if (validPage !== state.currentPage) {state.currentPage = validPage;renderPage();}
}// 缩放处理
function changeScale(delta) {state.scale = parseFloat(Math.max(state.MIN_SCALE, Math.min(state.scale + delta, state.MAX_SCALE)).toFixed(1));renderPage();
}// 鼠标滚轮缩放处理
function handleWheelZoom(e) {if (!e.ctrlKey) return;e.preventDefault();const delta = e.deltaY > 0 ? -state.ZOOM_STEP : state.ZOOM_STEP;changeScale(delta);
}// 启动应用
initEventListeners();

代码解释

  1. 导入 pdfjsLib 和 pdfjsWorker:借助 ES6 模块语法导入 pdfjs-dist 库和 pdf.worker.js
  2. 设置 worker 源:把 pdfjsLib.GlobalWorkerOptions.workerSrc 设为 pdfjsWorker,从而让 PDF.js 能够正确使用 Web Worker。
  3. 加载 PDF 文件:利用 pdfjsLib.getDocument 方法加载指定的 PDF 文件。
  4. 渲染第一页:获取 PDF 的第一页,创建一个 canvas 元素,然后把页面渲染到 canvas 上。
  5. 错误处理:使用 .catch 方法捕获并处理加载 PDF 文件时可能出现的错误。

运行 npm run dev
  VITE v6.3.5  ready in 1066 ms

访问  http://localhost:5173/index1.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/82212.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

精品,架构师总结,MySQL 5.7 查询入门详解

文章目录 MySQL 5.7 查询入门详解一、数据库与表基础操作1.1 连接数据库1.2 创建数据库1.3 使用数据库1.4 创建数据表1.5 表结构查看 二、SELECT基础查询2.1 全列查询2.2 指定列查询2.3 别名使用2.4 去重查询2.5 表达式计算 三、WHERE条件查询3.1 比较运算符3.2 逻辑运算符3.3 …

P48-56 应用游戏标签

这一段课主要是把每种道具的游戏Tag进行了整理与应用 AuraAbilitySystemComponentBase.h // Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "AbilitySystemComponent.h"…

【AWS+Wordpress】将本地 WordPress 网站部署到AWS

前言 自学笔记&#xff0c;解决问题为主&#xff0c;亲测有效&#xff0c;欢迎补充。 本地开发机&#xff1a;macOS&#xff08;Sequoia 15.0.1&#xff09; 服务器&#xff1a;AWS EC2&#xff08;Amazon Linux 2023&#xff09; 目标&#xff1a;从本地迁移 WordPress 到云…

从零开始:用PyTorch构建CIFAR-10图像分类模型达到接近1的准确率

为了增强代码可读性&#xff0c;代码均使用Chatgpt给每一行代码都加入了注释&#xff0c;方便大家在本文代码的基础上进行改进优化。 本文是搭建了一个稍微优化了一下的模型&#xff0c;训练200个epoch&#xff0c;准确率达到了99.74%&#xff0c;简单完成了一下CIFAR-10数据集…

C++复习类与对象基础

类的成员函数为什么需要在类外定义 1.1 代码组织与可读性​ ​类内定义​&#xff1a;适合 ​短小简单的函数​&#xff08;如 getter/setter&#xff09;&#xff0c;能直观体现类的接口设计。 ​类外定义​&#xff1a;当函数体较复杂时&#xff0c;将实现移到类外&#xf…

【计算机网络】Cookie、Session、Token之间有什么区别?

大家在日常使用浏览器时可能会遇到&#xff1a;是否清理Cookie&#xff1f;这个问题。 那么什么是Cookie呢&#xff1f;与此相关的还有Session、Token这些。这两个又是什么呢&#xff1f; 本文将对这三个进行讲解区分&#xff0c;如果对小伙伴有帮助的话&#xff0c;也请点赞、…

Python 3.x 内置装饰器 (4) - @dataclass

dataclass 是Python 3.7 引入的一个装饰器&#xff0c;用来简化创建数据类&#xff08;主要存储数据的类&#xff09;的过程。它会自动为类生成一些常用的方法&#xff0c;比如&#xff1a; __init__: 对象的初始化 __repr__: 定义类的官方字符串表示。 __eq__: 定义两个对象…

第一次被AI指点出文章的问题

二十年&#xff0c;几乎从未收到过这种程度的反馈。大部分意见都是有效的批评。 1.前言 关于链家左晖的一篇评论稿 这篇文章有什么问题吗&#xff1f;所有方面都可以谈&#xff0c;包括叙述&#xff0c;用词&#xff0c;重复&#xff0c;真实性&#xff0c;偏见&#xff0c;…

var、let、const三者之间的区别和使用

var、let、const 都是用于声明变量的关键字&#xff0c;可以通过作用域、可变性、变量提升几个方面进行区分&#xff1b; 1&#xff0c;作用域 1&#xff09;var的属于函数作用域&#xff0c;只能在函数内使用。若在函数外部声明变量&#xff0c;会变为全局变量&#xff1b; …

Consumer Group的作用是什么?Rebalance的触发条件有哪些? (实现消费者负载均衡;消费者加入/离开、订阅Topic变化等)

好的&#xff0c;我现在需要回答用户关于Kafka Consumer Group和Rebalance的问题。首先&#xff0c;用户问的是Consumer Group的作用以及Rebalance的触发条件。根据之前的对话历史&#xff0c;用户已经了解了Kafka的基本组件、消息保留策略、顺序性保证等&#xff0c;现在的问题…

出一期Source Insigned的使用教程

1. 创建新项目 打开 Source Insight&#xff0c;点击菜单栏的 Project > New Project。在弹出的窗口中&#xff0c;输入项目名称&#xff08;建议与项目内容相关&#xff0c;便于识别&#xff09;。指定项目数据文件的存储路径&#xff08;即 Source Insight 配置文件保存的…

A. Row GCD(gcd的基本性质)

Problem - 1458A - Codeforces 思路&#xff1a; 首先得知道gcd的两个基本性质&#xff1a; (1) gcd(a,b)gcd(a,|b-a|) (2) gcd(a,b,c)gcd(a,gcd(b,c)) 结合题目所给的a1bj&#xff0c;a2bj...... anbj 根据第一条性质得到&#xff1a; gcd(a1bj&#xff0c;a2bj)gcd(…

ES6入门---第三单元 模块三:async、await

async function fn(){ //表示异步&#xff1a;这个函数里面有异步任务 let result await xxx //表示后面结果需要等待 } 读取文件里数据实例&#xff1a; const fs require(fs);//简单封装 fs封装成一个promise const readFile function (fileName){return…

如何在 C# 和 .NET 中打印 DataGrid

DataGrid 是 .NET 架构中一个功能极其丰富的组件&#xff0c;或许也是最复杂的组件之一。写这篇文章是为了回答“我到底该如何打印 DataGrid 及其内容”这个问题。最初即兴的建议是使用我的屏幕截图文章来截取表单&#xff0c;但这当然无法解决打印 DataGrid 中虚拟显示的无数行…

C语言 指针(5)

目录 1.冒泡排序 2.二级指针 3.指针数组 4.指针数组模拟二级数组 1.冒泡排序 1.1 基本概念 冒泡排序&#xff08;Bubble Sort&#xff09; 是一种简单的排序算法&#xff0c;它重复地遍历要排序的数列&#xff0c;一次比较两个元 素&#xff0c;如果它们的顺序错误就把它…

15前端项目----用户信息/导航守卫

登录/注册 持久存储用户信息问题 退出登录导航守卫解决问题 持久存储用户信息 本地存储&#xff1a;&#xff08;在actions中请求成功时&#xff09; 添加localStorage.setItem(token,result.data.token);获取存储&#xff1a;&#xff08;在user仓库中&#xff0c;state中tok…

RSS 2025|斯坦福提出「统一视频行动模型UVA」:实现机器人高精度动作推理

导读 在机器人领域&#xff0c;让机器人像人类一样理解视觉信息并做出精准行动&#xff0c;一直是科研人员努力的方向。今天&#xff0c;我们要探讨的统一视频行动模型&#xff08;Unified Video Action Model&#xff0c;UVA&#xff09;&#xff0c;就像给机器人装上了一个“…

基于论文的大模型应用:基于SmartETL的arXiv论文数据接入与预处理(四)

上一篇介绍了基于SmartETL框架实现arxiv采集处理的基本流程&#xff0c;通过少量的组件定制开发&#xff0c;配合yaml流程配置&#xff0c;实现了复杂的arxiv采集处理。 由于其业务流程复杂&#xff0c;在实际应用中还存在一些不足需要优化。 5. 基于Kafka的任务解耦设计 5.…

Fiori学习专题三十五:Device Adaptation

由于在类似于手机的小面板上显示时&#xff0c;我们为了留出更多空间展示数据&#xff0c;可以将一些控件折叠。 1.修改HelloPanel.view.xml&#xff0c;加入expandable“{device>/system/phone}” expanded"{ !${device>/system/phone} <mvc:ViewcontrollerNam…

【记录】HunyuanVideo 文生视频工作流

HunyuanVideo 文生视频工作流指南 概述 本指南详细介绍如何在ComfyUI中使用腾讯混元HunyuanVideo模型进行文本到视频生成的全流程操作&#xff0c;包含环境配置、模型安装和工作流使用说明。 参考&#xff1a;https://comfyui-wiki.com/zh/install/install-comfyui/install-c…