iframe+URL参数是最轻量的翻页控制方式,需用#page=N(大小写敏感、同源)、配合zoom等参数,避免拼错或仅改hash;pdf.js提供精确控制但须等initializedPromise完成;预切图方案快但丧失文本能力。

iframe + URL 参数是最轻量的翻页控制方式
直接用 iframe 嵌入 PDF,配合 #page=N 参数就能跳转页码,无需 JS 解析、不依赖外部库,浏览器原生支持,兼容性好(Chrome/Firefox/Edge 都行,Safari 16.4+ 支持)。
常见错误是把参数拼错或没加 #:比如写成 doc.pdf?page=3 不生效,必须是 doc.pdf#page=3;另外参数名大小写敏感,Page 或 PAGE 都无效。
- 确保 PDF 文件同源(或服务端已配 CORS),否则
iframe.contentWindow.location.hash读不到当前页码 -
zoom参数可同步控制缩放,例如#page=2&zoom=FitH让页面顶部对齐视口 - 点击按钮前先更新
iframe.src,不要只改 hash —— 否则 Safari 可能不触发重载 - 页码从 1 开始计数,
#page=0会被忽略,#page=999超出总页数时自动定位到最后一页
PDF.js 的 pdfViewer.currentPage 是精确控制的关键
如果你需要逐页渲染、自定义 UI、禁用下载按钮或做页码校验,pdf.js 是唯一可靠选择。它把 PDF 解析为 Canvas,所有翻页逻辑由 JS 控制,不受浏览器 PDF 插件差异影响。
容易踩的坑是没等文档加载完成就调用翻页方法:pdfViewer 对象必须在 PDFViewerApplication.initializedPromise 解析后才可用,否则报 Cannot read property 'currentPage' of undefined。
立即学习“前端免费学习笔记(深入)”;
- 初始化后用
PDFViewerApplication.pdfViewer.currentPage = 5直接跳转,比手动调render()更稳 - 监听页码变化用
PDFViewerApplication.eventBus.on('pagechange', handler),别监听 window.hashchange - 总页数通过
PDFViewerApplication.pdfDocument.numPages获取,不是document.getElementById('viewer').children.length - 禁用下载按钮只需在 viewer.html 中删掉
<button id="download">,CSS 隐藏无效
用 insertAdjacentHTML 动态替换 iframe 不安全
有人试图用 JS 删除旧 iframe 再插入新 iframe 来“刷新”页码,这会导致 PDF 重新加载、状态丢失、滚动位置归零,且在某些浏览器中触发两次 onload。
正确做法是复用同一个 iframe 元素,只更新其 src 属性。如果发现页码没变,大概率是浏览器缓存了旧 URL —— 在 URL 后加时间戳参数无用,必须改变路径本身或强制清除 iframe 缓存。
- 推荐写法:
iframeEl.src = iframeEl.src.split('#')[0] + '#page=' + targetPage - 避免在 iframe 外层套
div并用innerHTML = ''清空 —— 这会销毁 iframe 实例,下次 src 赋值不触发加载 - 移动端 iOS Safari 对 iframe hash 变更响应慢,建议加
setTimeout(() => {}, 0)延迟触发
服务端预切图方案适合固定内容但丧失文本搜索能力
如果 PDF 内容不变、页数少(≤50)、对加载速度极度敏感,可提前用 Ghostscript 把 PDF 拆成 PNG,前端用 <img> 切换显示 —— 这样翻页快、无解析延迟、支持任意 CSS 动画。
代价很明确:无法选中文本、不能复制、不支持搜索、文件体积翻倍(尤其高 DPI 图像)、缩放失真。而且每换一页都要加载新图片,没有 PDF.js 的按需解码优化。
- 生成命令示例:
gs -dNOPAUSE -dBATCH -sDEVICE=png16m -r150 -sOutputFile=page-%03d.png book.pdf - 页码索引必须和服务端一致,前端不能靠
img.naturalWidth推算总页数 - 切换时用
img.src = 'pages/page-003.png',别用 background-image —— 后者无法设置 alt 和加载状态



















