老地方影院
31.02MB · 2025-11-04
PDF预览是Web开发中常见的需求,下面我将详细介绍各种Web端PDF预览方法,并提供一个完整的实现示例。
========================================================
这是最简单直接的PDF预览方法,适合快速实现基本预览功能。
<!-- 使用 iframe -->
<iframe src="document.pdf" width="100%" height="600px"></iframe>
<!-- 使用 embed -->
<embed src="document.pdf" width="100%" height="600px" type="application/pdf">
特点:
实现简单,一行代码即可
浏览器内置支持,无需额外依赖
功能有限,定制性差
在不同浏览器中表现可能不一致
PDF.js是Mozilla开发的纯JavaScript PDF渲染库,功能强大且高度可定制。
优势:
开源免费,由Mozilla维护
支持分页、缩放、文本选择、搜索等高级功能
跨浏览器兼容性好
可深度定制UI和交互
针对不同前端框架,有专门的PDF预览组件:
React: react-pdf、@react-pdf-viewer/core
Vue: vue-pdf、pdfvuer
Angular: ng2-pdf-viewer
下面是一个使用PDF.js实现的完整PDF预览器,包含分页、缩放和导航功能:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PDF预览器</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
            color: #333;
            line-height: 1.6;
            padding: 20px;
            min-height: 100vh;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: white;
            border-radius: 12px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
            overflow: hidden;
        }
        
        header {
            background: linear-gradient(90deg, #2c3e50, #4a6491);
            color: white;
            padding: 20px;
            text-align: center;
        }
        
        h1 {
            font-size: 2.2rem;
            margin-bottom: 10px;
        }
        
        .description {
            font-size: 1.1rem;
            opacity: 0.9;
            max-width: 800px;
            margin: 0 auto;
        }
        
        .content {
            padding: 30px;
        }
        
        .methods {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 20px;
            margin-bottom: 40px;
        }
        
        .method-card {
            background: #f8f9fa;
            border-radius: 10px;
            padding: 20px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
            transition: transform 0.3s, box-shadow 0.3s;
        }
        
        .method-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
        }
        
        .method-card h3 {
            color: #2c3e50;
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 2px solid #eaecef;
        }
        
        .method-card ul {
            list-style-type: none;
            margin-left: 10px;
        }
        
        .method-card li {
            margin-bottom: 8px;
            position: relative;
            padding-left: 20px;
        }
        
        .method-card li:before {
            content: "•";
            color: #4a6491;
            font-weight: bold;
            position: absolute;
            left: 0;
        }
        
        .demo-section {
            background: #f8f9fa;
            border-radius: 10px;
            padding: 25px;
            margin-top: 30px;
        }
        
        .demo-section h2 {
            color: #2c3e50;
            margin-bottom: 20px;
            text-align: center;
        }
        
        .pdf-viewer {
            border: 1px solid #e1e4e8;
            border-radius: 8px;
            overflow: hidden;
            background: white;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
        }
        
        .toolbar {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 15px 20px;
            background: #2c3e50;
            color: white;
        }
        
        .nav-controls {
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        button {
            background: #4a6491;
            color: white;
            border: none;
            padding: 8px 15px;
            border-radius: 5px;
            cursor: pointer;
            transition: background 0.3s;
            font-weight: 500;
        }
        
        button:hover {
            background: #3a5481;
        }
        
        button:disabled {
            background: #6c757d;
            cursor: not-allowed;
        }
        
        .page-info {
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        input[type="number"] {
            width: 60px;
            padding: 5px;
            border: 1px solid #ced4da;
            border-radius: 4px;
            text-align: center;
        }
        
        .zoom-controls {
            display: flex;
            align-items: center;
            gap: 10px;
        }
        
        .canvas-container {
            display: flex;
            justify-content: center;
            padding: 20px;
            background: #f1f3f5;
            min-height: 500px;
        }
        
        canvas {
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
            border: 1px solid #e1e4e8;
        }
        
        footer {
            text-align: center;
            margin-top: 40px;
            padding: 20px;
            color: #6c757d;
            font-size: 0.9rem;
            border-top: 1px solid #eaecef;
        }
        
        @media (max-width: 768px) {
            .toolbar {
                flex-direction: column;
                gap: 15px;
            }
            
            .nav-controls, .zoom-controls {
                width: 100%;
                justify-content: center;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <header>
            <h1>Web端PDF预览方法</h1>
            <p class="description">探索多种在Web应用中预览PDF文档的技术方案,从简单嵌入到高级定制</p>
        </header>
        
        <div class="content">
            <div class="methods">
                <div class="method-card">
                    <h3>1. 使用 <iframe> 或 <embed></h3>
                    <ul>
                        <li>实现简单,一行代码即可</li>
                        <li>浏览器内置支持</li>
                        <li>功能有限,定制性差</li>
                        <li>适合快速实现基本预览</li>
                    </ul>
                </div>
                
                <div class="method-card">
                    <h3>2. 使用 PDF.js</h3>
                    <ul>
                        <li>Mozilla开发的纯JS PDF渲染库</li>
                        <li>功能强大,高度可定制</li>
                        <li>支持分页、缩放、搜索等</li>
                        <li>跨浏览器兼容性好</li>
                    </ul>
                </div>
                
                <div class="method-card">
                    <h3>3. 使用第三方库/组件</h3>
                    <ul>
                        <li>React: react-pdf, @react-pdf-viewer</li>
                        <li>Vue: vue-pdf, pdfvuer</li>
                        <li>Angular: ng2-pdf-viewer</li>
                        <li>简化框架集成</li>
                    </ul>
                </div>
            </div>
            
            <div class="demo-section">
                <h2>PDF.js 预览演示</h2>
                <div class="pdf-viewer">
                    <div class="toolbar">
                        <div class="nav-controls">
                            <button id="prev-page" disabled>上一页</button>
                            <div class="page-info">
                                <span>页码:</span>
                                <input type="number" id="page-num" value="1" min="1">
                                <span id="page-count">/ 1</span>
                            </div>
                            <button id="next-page" disabled>下一页</button>
                        </div>
                        
                        <div class="zoom-controls">
                            <button id="zoom-out">缩小</button>
                            <span id="zoom-level">100%</span>
                            <button id="zoom-in">放大</button>
                        </div>
                    </div>
                    
                    <div class="canvas-container">
                        <canvas id="pdf-canvas"></canvas>
                    </div>
                </div>
            </div>
        </div>
        
        <footer>
            <p>PDF预览方案比较与实现示例 | 使用 PDF.js 2.10.377</p>
        </footer>
    </div>
    <!-- 引入PDF.js库 -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.10.377/pdf.min.js"></script>
    <script>
        // 设置PDF.js worker路径
        pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.10.377/pdf.worker.min.js';
        
        // 初始化变量
        let pdfDoc = null;
        let currentPage = 1;
        let totalPages = 0;
        let currentScale = 1.0;
        
        // 获取DOM元素
        const canvas = document.getElementById('pdf-canvas');
        const ctx = canvas.getContext('2d');
        const prevBtn = document.getElementById('prev-page');
        const nextBtn = document.getElementById('next-page');
        const pageNumInput = document.getElementById('page-num');
        const pageCountSpan = document.getElementById('page-count');
        const zoomOutBtn = document.getElementById('zoom-out');
        const zoomInBtn = document.getElementById('zoom-in');
        const zoomLevelSpan = document.getElementById('zoom-level');
        
        // 加载PDF文档
        const url = 'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/web/compressed.tracemonkey-pldi-09.pdf';
        
        pdfjsLib.getDocument(url).promise.then(pdf => {
            pdfDoc = pdf;
            totalPages = pdf.numPages;
            pageCountSpan.textContent = `/ ${totalPages}`;
            
            // 启用/禁用按钮
            updateButtons();
            
            // 渲染第一页
            renderPage(currentPage);
        }).catch(error => {
            console.error('加载PDF时出错:', error);
            alert('加载PDF文档时出错,请检查控制台获取详细信息。');
        });
        
        // 渲染指定页面
        function renderPage(pageNumber) {
            pdfDoc.getPage(pageNumber).then(page => {
                const viewport = page.getViewport({ scale: currentScale });
                
                // 设置canvas尺寸
                canvas.height = viewport.height;
                canvas.width = viewport.width;
                
                // 渲染PDF页面到canvas
                const renderContext = {
                    canvasContext: ctx,
                    viewport: viewport
                };
                
                page.render(renderContext).promise.then(() => {
                    console.log(`第 ${pageNumber} 页渲染完成`);
                });
            });
            
            // 更新页码输入框
            pageNumInput.value = pageNumber;
        }
        
        // 更新按钮状态
        function updateButtons() {
            prevBtn.disabled = currentPage <= 1;
            nextBtn.disabled = currentPage >= totalPages;
        }
        
        // 上一页
        prevBtn.addEventListener('click', () => {
            if (currentPage <= 1) return;
            currentPage--;
            renderPage(currentPage);
            updateButtons();
        });
        
        // 下一页
        nextBtn.addEventListener('click', () => {
            if (currentPage >= totalPages) return;
            currentPage++;
            renderPage(currentPage);
            updateButtons();
        });
        
        // 页码输入
        pageNumInput.addEventListener('change', () => {
            let desiredPage = parseInt(pageNumInput.value);
            
            if (desiredPage < 1) desiredPage = 1;
            if (desiredPage > totalPages) desiredPage = totalPages;
            
            currentPage = desiredPage;
            renderPage(currentPage);
            updateButtons();
        });
        
        // 缩小
        zoomOutBtn.addEventListener('click', () => {
            if (currentScale <= 0.5) return;
            currentScale -= 0.1;
            zoomLevelSpan.textContent = `${Math.round(currentScale * 100)}%`;
            renderPage(currentPage);
        });
        
        // 放大
        zoomInBtn.addEventListener('click', () => {
            if (currentScale >= 3.0) return;
            currentScale += 0.1;
            zoomLevelSpan.textContent = `${Math.round(currentScale * 100)}%`;
            renderPage(currentPage);
        });
    </script>
</body>
</html>
这是最简单的PDF预览方法,只需一行HTML代码即可实现。这种方法依赖浏览器内置的PDF查看器,因此在不同浏览器中可能会有不同的显示效果和功能。
优点:
实现极其简单
无需额外JavaScript代码
浏览器自动处理渲染和交互
缺点:
定制性差,无法自定义工具栏或添加额外功能
在不同浏览器中表现不一致
无法深度集成到应用UI中
PDF.js是功能最全面、最灵活的Web端PDF预览解决方案。它使用Canvas渲染PDF内容,提供了完整的API来控制PDF的显示和交互。
核心功能:
分页显示和导航
缩放控制
文本选择和搜索
打印支持
自定义UI和交互
实现步骤:
引入PDF.js库
加载PDF文档
获取页面并渲染到Canvas
添加控制逻辑(翻页、缩放等)
对于使用现代前端框架的项目,使用专门的PDF组件可以简化集成过程:
React示例:
import { Viewer, Worker } from '@react-pdf-viewer/core';
import '@react-pdf-viewer/core/lib/styles/index.css';
function PDFViewer() {
  return (
    <Worker workerUrl="https://unpkg.com/[email protected]/build/pdf.worker.min.js">
      <Viewer fileUrl="/document.pdf" />
    </Worker>
  );
}
Vue示例:
<template>
  <div>
    <pdf src="/document.pdf"></pdf>
  </div>
</template>
<script>
import pdf from 'vue-pdf'
export default {
  components: {
    pdf
  }
}
</script>
简单场景:使用<iframe>或<embed>标签
需要定制功能:使用PDF.js
框架项目:使用对应的PDF组件库
移动端优先:考虑使用Google Docs预览链接
以上方案覆盖了Web端PDF预览的绝大多数需求,您可以根据具体项目需求选择最适合的方法。