移动端 PDF 在线预览

在 H5、微信内置浏览器环境直接打开 PDF,不同系统原生行为差异很大。iOS 微信可以直接预览 PDF,但不支持二次定制 UI、转发;安卓微信会直接触发文件下载,无法在线阅读。

主流解决方案:使用 Mozilla PDF.js,在前端把PDF解析渲染为 Canvas / SVG,实现在线预览,可自定义页面逻辑、分享转发。

Word文档无法前端直接解析,一般由后端预转换为PDF或图片序列。

微信内置浏览器原生PDF预览行为

系统 表现 限制
iOS(iPhone) 微信内置内核直接打开PDF,在线预览 页面是微信内置页面,无法自定义UI、无法直接做业务转发分享;复杂排版Word转PDF后偶有排版错乱
Android 点击PDF链接直接跳转下载,不会在线预览 用户必须下载文件后,使用本地APP打开阅读

原生预览能力不可控,业务需要统一体验、自定义交互(分享、水印、翻页)时,必须引入PDF.js。

Word文档预览说明:浏览器前端没有成熟方案直接解析Word。建议后端预处理,将Word转PDF,再交给前端PDF预览组件;也可以后端直接转图片序列展示。

注意:Linux服务端转换复杂图文文档,容易出现图文错位;Windows服务器转换成本高,第三方云转换服务有付费开销。

PDF.js 基础原理

PDF.js 是 Mozilla 开源、基于HTML5的PDF解析渲染库,不依赖任何浏览器插件

  • PDF解析的CPU密集计算放到 Web Worker 子线程执行,避免阻塞主线程造成页面卡顿;
  • 解析PDF文档结构,逐页渲染输出为 Canvas 位图 或者 SVG 矢量DOM;
  • 主线程拿到渲染结果,挂载DOM展示给用户。

API全部基于Promise异步,适合异步处理大体积PDF文件。

CDN 直接引入

<div id="pdf_viewer"></div>
<script type="module">
  import * as pdfjsLib from 'https://cdn.jsdelivr.net/npm/pdfjs-dist@4/build/pdf.min.mjs';
  // worker 路径必须与 pdfjs-dist 主库版本一致;v4 起文件名是 .mjs
  pdfjsLib.GlobalWorkerOptions.workerSrc =
    'https://cdn.jsdelivr.net/npm/pdfjs-dist@4/build/pdf.worker.min.mjs';

  async function renderPdf(pdfUrl) {
    // 加载pdf文档
    const pdf = await pdfjsLib.getDocument(pdfUrl).promise;
    const totalPages = pdf.numPages;

    for(let pageNo = 1; pageNo <= totalPages; pageNo++) {
      const page = await pdf.getPage(pageNo);
      const scale = 1.5;
      const viewport = page.getViewport({scale});

      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      document.getElementById('pdf_viewer').appendChild(canvas);

      canvas.width = viewport.width;
      canvas.height = viewport.height;

      await page.render({
        canvasContext: ctx,
        viewport
      }).promise;
    }
  }
  renderPdf("./demo.pdf");
</script>

npm 引入

安装依赖

npm install pdfjs-dist -S
import * as PDFJS from 'pdfjs-dist';
// 设置 worker 脚本路径,webpack、vite 需要处理 worker 资源
PDFJS.GlobalWorkerOptions.workerSrc = new URL(
  'pdfjs-dist/build/pdf.worker.min.mjs',
  import.meta.url
).toString();

async function renderPdf(pdfUrl) {
  const pdfDoc = await PDFJS.getDocument(pdfUrl).promise;
  // 渲染逻辑和上面示例 renderPageAsync 保持一致
}

pdfh5:移动端封装PDF组件

pdfh5 底层封装pdf.js,存在两种渲染模式:

  • canvas模式:PDF页面渲染到Canvas画布(内存位图,浏览器DOM里的<canvas>元素,不是导出静态图片文件;如果DPR处理不当,移动端会模糊);
  • svg模式:输出SVG矢量DOM节点,文本可复制。

两种模式区别:

  • canvas模式:兼容性最好,支持印章、签名PDF;不开启textLayer时文本不可选;需要手动处理devicePixelRatio避免模糊。
  • 旧版svg模式:矢量、文本可复制;但对带签名、印章、复杂混合图层PDF渲染会异常,新版已经移除该模式。

版本更新:v3.0.0(2025-10)支持官方 pdf.js v5.4.296,移除 svg 渲染模式,恢复懒加载,新增分段加载、沙箱集成(防止 JavaScript 注入等)、密码 PDF 预览;手势缩放仍在优化。v2.0.5 起已移除 jQuery 依赖。

CDN 直接引入(v2.x旧版本)

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pdfh5@2/lib/pdfh5.css">
<div id="pdf_viewer"></div>
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.4/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/pdfh5@2/lib/pdfh5.js"></script>

<script>
new window.Pdfh5('#pdf_viewer', {
  pdfurl: "./demo.pdf",
  // 处理中文CID字体,解决中文乱码
  cMapUrl: "https://cdn.jsdelivr.net/npm/pdfjs-dist@2/cmaps/",
  renderType: "canvas" // v2.x可选 canvas / svg;v3.x已删除svg
})
</script>

注意:pdfh5 内部大量硬编码相对路径、动态 import、worker 加载逻辑,依赖脚本与页面同源;公共 CDN 是跨域来源,浏览器安全机制把相对路径全部解析坏掉,因此 CDN 外链会各种诡异报错。

建议:把资源完整下载,放到自己业务服务器同源目录,本地<script>引入,不要引用第三方 CDN 地址。

Vue 项目使用(v3 版本)

<template>
  <div id="pdf_viewer"></div>
</template>

<script>
import Pdfh5 from "pdfh5";
import "pdfh5/css/pdfh5.css";

export default {
  data() {
    return {
      pdfh5Ins: null
    }
  },
  mounted() {
    this.pdfh5Ins = new Pdfh5("#pdf_viewer", {
      pdfurl: "./demo.pdf",
      // v3 版本已无 renderType 配置,固定 canvas 渲染
      textLayer: true, // 开启文本层,支持复制文字
      workerSrc: "./pdf.worker.min.js",
      cMapUrl: "./cmaps/"
    });
    // 监听渲染完成事件
    this.pdfh5Ins.on("complete", (status, msg, time) => {
      console.log("pdf渲染完成", status, msg);
    })
  },
  beforeDestroy() {
    // 销毁实例释放资源,防止内存泄漏
    this.pdfh5Ins && this.pdfh5Ins.destroy();
  }
}
</script>

v3 初始化时建议同时指定同源的 workerSrccMapUrl,并把仓库内的 cmaps、wasm、worker 拷到 public。是否还要单独 import CSS,以当前版本目录为准。

常见问题

PDF 跨域访问报错

PDF 文件如果和前端页面不在同一个域名,浏览器会触发 CORS 跨域拦截。

解决方案

  • 开发环境:webpack-dev-server 配置代理转发 PDF 资源
  • 服务端、Nginx:PDF 资源服务器配置 CORS 响应头,允许前端域名访问;
  • 后端接口代理:后端接收 PDF URL,把 PDF 读取为二进制 ArrayBuffer 返回给前端,前端传入二进制数据给 PDF.js 解析,绕过浏览器跨域限制。

中文 PDF 乱码、文字方块

PDF 内部使用 CID 东亚字体,缺少 cmaps 字符映射资源,就会出现中文乱码。

  • 配置参数 cMapUrl,指向 cmaps 字符映射资源;
  • 业务打包时不要把整份 cmaps 打进主 bundle。pdf.js 可从 CDN 拉 cmap;pdfh5 建议把 cmaps 放到与页面同源的静态目录,避免跨域和相对路径解析失败。

Canvas 渲染页面模糊

canvas 默认 CSS 像素渲染,手机高 DPR 屏幕会模糊。

需要根据 window.devicePixelRatio 设置 canvas 画布实际像素尺寸提升清晰度,pdfh5 内部 scale 参数可调节。

选型建议

  • 快速业务开发,需要封装好手势缩放、分页:选用 pdfh5 v3.x,v3 已无 jQuery 依赖,仅 canvas 渲染;
  • 需要深度自定义渲染逻辑:直接使用原生 pdfjs-dist
  • Word 文档:不要尝试前端解析,后端转换 PDF 或者图片序列。

参考链接

PDF.js官方仓库

pdfh5 github

© lizhao all right reserved,powered by Gitbook文件修订时间: 2026-09-03 01:39:37

results matching ""

    No results matching ""