reactHooks+antd+react-pdf封装pdf预览组件
1、下载插件:
npm i react-pdf
2、PdfPreview/index.tsx
/* 进入该组件时,通过路由传递path进来,形如: history.push({ pathname: '/pdfPreview', query: { path } }) */ import React, { useState } from 'react' import { Spin, Tooltip, Input } from 'antd' import { LeftOutlined, RightOutlined, PlusCircleOutlined, MinusCircleOutlined, FullscreenOutlined, FullscreenExitOutlined, ArrowLeftOutlined } from '@ant-design/icons' import styles from './index.less' import { Document, Page, pdfjs } from 'react-pdf' pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js` import { history } from 'umi' const PdfPreview: React.FC<{}> = (Props: any) => { const [pageNumber, setPageNumber] = useState(1) const [pageNumberInput, setPageNumberInput] = useState(1) const [pageNumberFocus, setPageNumberFocus] = useState(false) const [numPages, setNumPages] = useState(1) const [pageWidth, setPageWidth] = useState(600) const [fullscreen, setFullscreen] = useState(false) const { location } = history const { path }: any = location.query const onDocumentLoadSuccess = ({ numPages }: any) => { setNumPages(numPages) } const lastPage = () => { if (pageNumber == 1) return const page = pageNumber - 1 setPageNumber(page) setPageNumberInput(page) } const nextPage = () => { if (pageNumber === numPages) return const page = pageNumber + 1 setPageNumber(page) setPageNumberInput(page) } const onPageNumberFocus = (e: any) => { setPageNumberFocus(true) } const onPageNumberBlur = (e: any) => { setPageNumberFocus(false) setPageNumberInput(pageNumber) } const onPageNumberChange = (e: any) => { let value = e.target.value value = value <= 0 ? 1 : value value = value >= numPages ? numPages : value setPageNumberInput(value) } const toPage = (e: any) => { setPageNumber(Number(e.target.value)) } const pageZoomOut = () => { if (pageWidth <= 600) return const width = pageWidth * 0.8 setPageWidth(width) } const pageZoomIn = () => { const width = pageWidth * 1.2 setPageWidth(width) } const pageFullscreen = () => { if (fullscreen) { setFullscreen(false) setPageWidth(600) } else { setFullscreen(true) setPageWidth(window.screen.width - 40) } } return ( <div className={styles.view}> <ArrowLeftOutlined className={styles.back} onClick={() => history.goBack()} /> <div className={styles.pageContainer}> <Document file={path} onLoadSuccess={onDocumentLoadSuccess} loading={<Spin size="large" />}> <Page pageNumber={pageNumber} width={pageWidth} loading={<Spin size="large" />} /> </Document> </div> <div className={styles.pageTool}> <Tooltip title={pageNumber == 1 ? '已是第一页' : '上一页'}> <LeftOutlined className={styles.outlined} onClick={lastPage} /> </Tooltip> <Input value={pageNumberFocus ? pageNumberInput : pageNumber} onFocus={onPageNumberFocus} onBlur={onPageNumberBlur} onChange={onPageNumberChange} onPressEnter={toPage} type="number" /> / {numPages} <Tooltip title={pageNumber == numPages ? '已是最后一页' : '下一页'}> <RightOutlined className={styles.outlined} onClick={nextPage} /> </Tooltip> <Tooltip title="放大"> <PlusCircleOutlined className={styles.outlined} onClick={pageZoomIn} /> </Tooltip> <Tooltip title="缩小"> <MinusCircleOutlined className={styles.outlined} onClick={pageZoomOut} /> </Tooltip> <Tooltip title={fullscreen ? '恢复默认' : '适合窗口'}> {fullscreen ? ( <FullscreenExitOutlined className={styles.outlined} onClick={pageFullscreen} /> ) : ( <FullscreenOutlined className={styles.outlined} onClick={pageFullscreen} /> )} </Tooltip> </div> </div> ) } export default PdfPreview
PdfPreview/index.less

.view { display: flex; justify-content: center; height: calc(100vh - 206px); padding: 20px 0; overflow: auto; background: #444; .back { position: absolute; top: 0; left: 0; color: #fff; font-size: 20px; transition: color .3s; width: 40px; line-height: 30px; background-color: red; } .back:hover { // color: #1890ff; } .pageContainer { width: max-content; max-width: 100%; box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 4px 0px; } .pageTool { position: absolute; bottom: 20px; padding: 8px 15px; color: white; background: rgb(66, 66, 66); border-radius: 15px; .outlined { margin: 0 10px; user-select: none; } input { display: inline-block; width: 50px; height: 24px; margin-right: 10px; text-align: center; } input::-webkit-outer-spin-button, input::-webkit-inner-spin-button { -webkit-appearance: none; } input[type='number'] { -moz-appearance: textfield; } } }
3、效果:
分类:
react
, ant-design
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· 地球OL攻略 —— 某应届生求职总结