🔥 用 Vue2 + PDF.js 手撸一个「PDF 连续预览器」,自适应屏幕、支持缩放,直接拿来用!

🌈 前言

最近做项目,产品丢过来一个需求: "我们要一个像掘金文章那样的 PDF 连续预览功能,要自适应屏幕,还要支持放大缩小!"

我心想,这需求简单啊,直接搜一波现成的库,结果一看,要么太重,要么不支持连续预览,要么缩放体验差,要么样式丑。

于是,干脆自己撸一个!用 Vue2 + PDF.js ,花了一个下午,效果还不错,直接分享给大家,代码已经整理好了,复制粘贴就能用!

🚀 效果展示

  • ✅ 支持 PDF 文件上传预览
  • 连续滚动 显示所有页面,像浏览网页一样
  • 自适应屏幕宽度,窗口大小变化自动调整
  • 支持缩放(放大、缩小、重置)
  • 加载进度提示,体验更友好
  • 样式美观,代码简洁易读

📦 技术栈

  • Vue2:熟悉的响应式框架
  • PDF.js:Mozilla 出品的 PDF 渲染库,功能强大
  • FontAwesome:图标库,让按钮更美观

🛠️ 核心实现思路

1. 引入依赖

js 复制代码
<!-- Vue2 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<!-- PDF.js -->
<script src="https://cdn.jsdelivr.net/npm/pdfjs-dist@3.4.120/build/pdf.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/pdfjs-dist@3.4.120/build/pdf.worker.min.js"></script>
<!-- FontAwesome -->
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">

2. 文件上传

使用 <input type="file" accept=".pdf"> 实现文件选择,通过 FileReader 读取文件内容:

jshandleFileUpload(e) 复制代码
  const file = e.target.files[0];
  if (!file || file.type !== 'application/pdf') {
    this.errorMessage = '请上传PDF格式的文件';
    return;
  }

  const fileReader = new FileReader();
  fileReader.onload = (event) => {
    const typedArray = new Uint8Array(event.target.result);
    this.loadPdf(typedArray);
  };
  fileReader.readAsArrayBuffer(file);
}

3. 渲染 PDF 页面

使用 PDF.js 的 getDocument 方法加载 PDF,然后逐页渲染:

js 复制代码
renderPage(pageNum, containerWidth) {
  this.pdfDoc.getPage(pageNum).then(page => {
    const canvas = document.createElement('canvas');
    const context = canvas.getContext('2d');

    // 计算缩放比例,自适应容器宽度
    const viewport = page.getViewport({ scale: 1 });
    const baseScale = Math.min(containerWidth / viewport.width, 2);
    const scale = baseScale * this.zoom;
    const scaledViewport = page.getViewport({ scale });

    canvas.height = scaledViewport.height;
    canvas.width = scaledViewport.width;

    const renderContext = {
      canvasContext: context,
      viewport: scaledViewport
    };

    page.render(renderContext).promise.then(() => {
      this.loadedPages++;
    });
  });
}

4. 缩放功能

通过调整 zoom 值,重新渲染所有页面:

js 复制代码
zoomIn() {
  if (this.zoom < 3) {
    this.zoom += 0.1;
    this.reRenderAllPages();
  }
},
zoomOut() {
  if (this.zoom > 0.3) {
    this.zoom -= 0.1;
    this.reRenderAllPages();
  }
},
resetZoom() {
  this.zoom = 1.0;
  this.reRenderAllPages();
}

5. 自适应屏幕

监听窗口大小变化,自动重新渲染:

js 复制代码
mounted() {
  window.addEventListener('resize', () => {
    if (this.pdfDoc && this.showViewer) {
      this.reRenderAllPages();
    }
  });
}

📝 使用方式

  1. 复制文章开头提供的完整 HTML 代码
  2. 保存为 index.html
  3. 直接双击打开即可使用

🏁 结语

一个简单的 PDF 连续预览器就完成了,代码不到 300 行,功能却很实用。如果你有更好的想法或者遇到问题,欢迎在评论区留言交流!

相关推荐
excel43 分钟前
Vue 3 实现高性能虚拟列表:Spacer 占位 vs Absolute 定位,哪种更优?
前端
SoaringHeart1 小时前
Flutter进阶:实现比赛对阵图/淘汰赛
前端·flutter
.用户昵称已存在.2 小时前
HTML 核心元素实战:超链接、iframe 框架与 form 表单全面解析
前端·microsoft·html
太过平凡的小蚂蚁5 小时前
Kotlin 协程作用域
vue.js·elementui·kotlin
MediaTea11 小时前
Python 第三方库:lxml(高性能 XML/HTML 解析与处理)
xml·开发语言·前端·python·html
西陵11 小时前
Nx带来极致的前端开发体验——使用MF进行增量构建
前端·javascript·架构
Nicholas6811 小时前
flutter滚动视图之ProxyWidget、ProxyElement、NotifiableElementMixin源码解析(九)
前端
JackieDYH11 小时前
vue3中reactive和ref如何使用和区别
前端·javascript·vue.js
伍哥的传说12 小时前
解密 Vue 3 shallowRef:浅层响应式 vs 深度响应式的性能对决
javascript·vue.js·ecmascript·vue3.js·大数据处理·响应式系统·shallowref