react实现移动端pdf
React 实现移动端 PDF 预览与操作
在移动端实现 PDF 预览和操作,可以使用以下方法:
使用 react-pdf 库
安装依赖包:
npm install react-pdf
基础实现代码:
import { Document, Page } from 'react-pdf';
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
import 'react-pdf/dist/esm/Page/TextLayer.css';
function PDFViewer() {
const [numPages, setNumPages] = useState(null);
const [pageNumber, setPageNumber] = useState(1);
function onDocumentLoadSuccess({ numPages }) {
setNumPages(numPages);
}
return (
<div style={{ width: '100%' }}>
<Document
file="/sample.pdf"
onLoadSuccess={onDocumentLoadSuccess}
>
<Page pageNumber={pageNumber} width={window.innerWidth} />
</Document>
<p>
Page {pageNumber} of {numPages}
</p>
</div>
);
}
移动端优化要点
- 设置
width={window.innerWidth}使 PDF 适配屏幕宽度 - 添加手势支持实现翻页
- 添加缩放功能(需结合
transform: scale()) - 使用 CSS 媒体查询优化移动端样式
替代方案:PDF.js + React 对于更复杂的需求,可以直接使用 Mozilla 的 PDF.js:
import * as pdfjsLib from 'pdfjs-dist';
async function loadPDF(url) {
const loadingTask = pdfjsLib.getDocument(url);
const pdf = await loadingTask.promise;
// 获取第一页
const page = await pdf.getPage(1);
const viewport = page.getViewport({ scale: 1.0 });
// 渲染到canvas
const canvas = document.getElementById('pdf-canvas');
const context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
const renderContext = {
canvasContext: context,
viewport: viewport
};
await page.render(renderContext).promise;
}
移动端专用功能实现
- 双指缩放:监听
touchmove事件计算手指距离变化 - 单指滑动翻页:监听
touchstart和touchend计算滑动方向 - 长按选择文本:通过 PDF.js 的文本层实现
- 夜间模式:使用 CSS filter 反转颜色
性能优化建议
- 实现分页加载,避免一次性渲染所有页面
- 使用 Web Worker 处理 PDF 解析
- 添加加载进度指示器
- 对低端设备降低默认渲染质量
完整移动端示例组件
import { useState, useRef, useEffect } from 'react';
import { Document, Page } from 'react-pdf';
function MobilePDFViewer({ url }) {
const [numPages, setNumPages] = useState(0);
const [pageNumber, setPageNumber] = useState(1);
const [scale, setScale] = useState(1);
const startX = useRef(0);
const handleTouchStart = (e) => {
startX.current = e.touches[0].clientX;
};
const handleTouchEnd = (e) => {
const endX = e.changedTouches[0].clientX;
const diffX = startX.current - endX;
if (Math.abs(diffX) > 50) {
setPageNumber(prev => {
const newPage = diffX > 0 ? prev + 1 : prev - 1;
return Math.max(1, Math.min(numPages, newPage));
});
}
};
return (
<div
style={{
touchAction: 'none',
overflow: 'hidden'
}}
onTouchStart={handleTouchStart}
onTouchEnd={handleTouchEnd}
>
<Document
file={url}
onLoadSuccess={({ numPages }) => setNumPages(numPages)}
>
<Page
pageNumber={pageNumber}
width={window.innerWidth * scale}
/>
</Document>
<div style={{
position: 'fixed',
bottom: 20,
left: 0,
right: 0,
textAlign: 'center'
}}>
<button onClick={() => setScale(s => Math.min(2, s + 0.2))}>+</button>
<span> {pageNumber}/{numPages} </span>
<button onClick={() => setScale(s => Math.max(0.5, s - 0.2))}>-</button>
</div>
</div>
);
}
注意事项
- 在 iOS 上需要确保 PDF 文件通过 HTTPS 访问
- 大文件需要实现流式加载
- 考虑添加离线缓存支持
- 测试不同移动浏览器的兼容性
以上实现可以根据具体需求进行调整,关键是根据移动端特性优化交互体验。







