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();
代碼解釋
- 導入?
pdfjsLib
?和?pdfjsWorker
:借助 ES6 模塊語法導入?pdfjs-dist
?庫和?pdf.worker.js
。 - 設置 worker 源:把?
pdfjsLib.GlobalWorkerOptions.workerSrc
?設為?pdfjsWorker
,從而讓 PDF.js 能夠正確使用 Web Worker。 - 加載 PDF 文件:利用?
pdfjsLib.getDocument
?方法加載指定的 PDF 文件。 - 渲染第一頁:獲取 PDF 的第一頁,創建一個 canvas 元素,然后把頁面渲染到 canvas 上。
- 錯誤處理:使用?
.catch
?方法捕獲并處理加載 PDF 文件時可能出現的錯誤。
運行 npm run dev
? VITE v6.3.5 ?ready in 1066 ms
訪問??http://localhost:5173/index1.html