admin管理员组文章数量:1649937
前段时间在react项目中接到了一个需求: 能够预览PDF 和 图片
接下来总结并记录一下:
用到的插件是react-pdf
我所实现的功能如下:可以鼠标点击翻页,可以鼠标上下滑动翻页,可以放大、缩小,可以跳转到指定页面。
- 首先封装pdf.js 的组件:
其中自己封装了四个icon的组件:nextPage、 lastPage 、zoomOut 、zoomIn (后面会说明封装组件的具体步骤,慢慢期待吧~)
但也可以用antd中的icon组件来实现
/* eslint-disable jsx-a11y/no-static-element-interactions */
import { useEffect, useState } from "react"
import { Document, Page, pdfjs } from "react-pdf"
import { toast } from "react-toastify"
import "./preview.scss"
import { Card, Input } from "reactstrap"
import Nextpage from "../components/Icons/Nextpage"
import Lastpage from "../components/Icons/Lastpage"
import Zoomin from "../components/Icons/Zoomin"
import Zoomout from "../components/Icons/Zoomout"
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cat/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`
function MyApp({ file = " " }) {
const [numPages, setNumPages] = useState(1)
const [pageNumber, setPageNumber] = useState(1)
const [scale, setScale] = useState(1)
const fileType = file.split(";")[0].split("/")[1]
const [pageNumberFocus, setPageNumberFocus] = useState(false)
const [pageNumberInput, setPageNumberInput] = useState(1)
const [fullscreen, setFullscreen] = useState(false)
function onDocumentLoadSuccess({ numPages }) {
setNumPages(numPages)
setPageNumber(pageNumber)
}
useEffect(
() => {
window.addEventListener("scroll", handleScroll, true)
return () => {
window.removeEventListener("scroll", handleScroll, true)
}
},
[pageNumber, numPages], // eslint-disable-line react-hooks/exhaustive-deps
handleScroll
)
function handleScroll(e) {
let height = e.srcElement.documentElement.scrollTop + e.srcElement.documentElement.clientHeight
height = Math.ceil(height)
let scrollTop = e.srcElement.documentElement.scrollTop
let scrollHeight = e.srcElement.documentElement.scrollHeight
if (pageNumber !== 1 && scrollTop === 0) {
const page = pageNumber - 1
setPageNumber(page)
setPageNumberInput(page)
window.scrollTo(0, 10)
}
if (pageNumber !== numPages && height >= scrollHeight - 10) {
const page = pageNumber + 1
setPageNumber(page)
setPageNumberInput(page)
window.scrollTo(0, 10)
}
}
// 上一页 (lastPage)
function lastPage() {
if (pageNumber === 1) {
toast.info("This is the first page", 2)
return
}
const page = pageNumber - 1
setPageNumber(page)
setPageNumberInput(page)
}
//下一页(nextPage)
function nextPage() {
if (pageNumber === numPages) {
toast.info("This is the last page", 2)
return
}
const page = pageNumber + 1
setPageNumber(page)
setPageNumberInput(page)
}
// 跳转页面
function onPageNumberFocus() {
setPageNumberFocus(true)
}
function onPageNumberBlur() {
setPageNumberFocus(false)
setPageNumberInput(pageNumber)
}
function onPageNumberChange(e) {
let value = e.target.value
value = value <= 0 ? 1 : value
value = value >= numPages ? numPages : value
setPageNumberInput(value)
}
function handleKeyDown(e) {
if (e.keyCode === 13) {
setPageNumber(Number(e.target.value))
}
}
//缩小(ZoomOut)
function pageZoomOut() {
if (scale <= 0.5) {
toast.info("Zoomed to minimum", 2)
return
}
let newScale = scale - 0.1
setScale(newScale)
}
//放大(ZoomIn)
function pageZoomIn() {
if (scale >= 5) {
return
}
let newScale = scale + 0.1
setScale(newScale)
}
return (
<div className='preview-pdf-wrap'>
<div className='content-wrap'>
{file && (
<Card className='cardItem' bordered={false}>
{fileType === "jpg" || fileType === "png" || fileType === "jpeg" ? (
<div className='img-wrap'>
<img src={file} style={{ width: "100vw" }} alt='Red dot' />
</div>
) : (
<div className='pageContainer'>
<Document file={file} onLoadSuccess={onDocumentLoadSuccess}>
<Page pageNumber={pageNumber} scale={scale} width={window.innerWidth} />
</Document>
</div>
)}
</Card>
)}
<p>
Page {pageNumber} of {numPages}
</p>
</div>
{fileType === "pdf" && (
<div className='footer-wrap'>
<div className='pageTool'>
<div className='btn-wrap' title='last page'>
<div className='btn-icon' onClick={lastPage}>
<Lastpage type='icon-xiayiyehouyiye' />
</div>
</div>
<Input
value={pageNumberFocus ? pageNumberInput : pageNumber}
onFocus={onPageNumberFocus}
onBlur={onPageNumberBlur}
onChange={onPageNumberChange}
onKeyDown={handleKeyDown}
/>
/ {numPages}
<div className='btn-wrap' title='next page'>
<div className='btn-icon' onClick={nextPage}>
<Nextpage type='icon-xiayiyehouyiye' />
</div>
</div>
<div className='btn-wrap' title='zoomIn'>
<div className='btn-icon' onClick={pageZoomIn}>
<Zoomout type='plus' />
</div>
</div>
<div className='btn-wrap' title='zoomOut'>
<div className='btn-icon' onClick={pageZoomOut}>
<Zoomin type='icon-suoxiao1' style={{ textAlign: "center" }} />
</div>
</div>
</div>
</div>
)}
</div>
)
}
export default MyApp
- 下面是样式文件:preview.scss
.preview-pdf-wrap {
display: flex;
flex-direction: column;
justify-content: center;
flex-wrap: nowrap;
margin: 0 auto;
padding: 20px 0;
.content-wrap {
height: calc(100vh - 94px);
.cardItem {
.img-wrap {
padding-top: 112px;
img {
position: relative;
display: flex;
justify-content: center;
align-items: center;
transform: scale(0.3, 0.3);
}
}
}
.react-pdf__Document {
.react-pdf__Page {
width: fit-content;
margin: 0 auto;
}
}
}
.footer-wrap {
color: #fff;
width: 100%;
height: 64em;
display: flex;
justify-content: center;
flex-direction: column;
.pageTool {
position: fixed;
margin: 0 auto;
bottom: 10%;
left: 50%;
transform: translateX(-50%);
height: 74px;
align-items: center;
height: 45px;
background: #333;
opacity: 0.9;
border-radius: 16px;
display: flex;
flex-wrap: nowrap;
justify-content: space-between;
width: 30%;
input {
display: inline-block;
width: 30px;
text-align: center;
margin-right: 10px;
height: 15px;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
}
input[type="number"] {
-moz-appearance: textfield;
}
}
.btn-wrap {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
.btn-icon {
cursor: pointer;
}
}
button {
font-size: 12px;
width: 70px;
height: 35px;
border-radius: 7px;
}
.Nextpage {
text-align: center;
}
}
}
这里说一下最初打开PDF时自适应问题, 官方对scale做了解释的, 具体如下:
所以我在这把scale的默认值为1 ,然后写了宽度,如下:
const [scale, setScale] = useState(1)
<Page pageNumber={pageNumber} scale={scale} width={window.innerWidth} />
- 最后来说明怎么去使用这些封装好的组件:
preview.js 文件中使用, 这个文件我直接创建在同一个目录的~ 这个可以根据自己的具体情况而定哟~
import Pdf from "./pdf"
import { data } from "./data"
export default function Home() {
return (
<>
<Pdf file={data} />
</>
)
}
- 接下来是data文件,因为我没用的是base64 ,所以单独创建了data.js 文件, 在这因为数据太长就不放了,这个数据你可以自己放上去哈,如果不是base64的要求,那就不用data.js 文件,直接放文件地址就可以实现的哦。
export const data =" // 在这填写对应pdf文件的base64 数据,在此要注意pdf文件格式(一般是一下格式:data:application/pdf;base64 )"
我也给大家推荐一个把文件转换为base64 数据的网站:文件Base64在线编码和解码工具
能够坚持看到这儿就很棒了!! 给自己一个大大的赞吧~
欣赏一波樱花嘻嘻嘻
到这儿就大功告成了~ 不是很清晰的欢迎私信或者留言哦
如果还想看 上面说的icon 组件的封装的话那我们继续哈
下面来说一下icon组件的封装,组件的封装方式都一样,所以在这只说明一个,目录的话,如果你在项目里做的话要在组件库中创建哦,如果自己单独实现的话也尽量自己创建组件库再封装,具体看自己的习惯哦~ 不多唠叨了, 直接上代码吧~
nextPage.js文件的内容如下: 在封装这个组件的时候顺便可以看看svg的应用~
const Nextpage = () => {
return (
<div style={{ textAlign: "center" }} aria-hidden="true" role="presentation">
<svg
style={{ width: "24px", height: "23px" }}
aria-hidden="true"
focusable="false"
data-prefix="fal"
data-icon="arrows-h"
className="icon-xiayiyehouyiye"
viewBox="0 0 1024 1024"
>
<path
d="M639.7 490.3l-1.8-1.8-21.8-21.8L430.4 281c-12.4-12.5-32.8-12.5-45.2-0.1-12.4 12.5-12.4 32.9 0 45.3L570.9 512 385.1 697.7c-12.4 12.5-12.4 32.9 0 45.3 12.5 12.4 32.9 12.4 45.3 0l185.7-185.7 21.5-21.5 2.2-2.2c5.2-5.7 8.3-13.2 8.3-21.5 0.1-8.4-3.1-16.1-8.4-21.8z"
fill="#fff"
/>
</svg>
</div>
)
}
export default Nextpage
index 文件:
import Nextpage from "./Nextpage"
export default Nextpage
封装好后直接引入就可以了, 是不是so easy 吖 哈哈哈
图片的预览暂时不在这讲了,可能后期会更新博客说明一下的哦,没更新的话可以私信或留言哦~
一起努力吖!加油~
版权声明:本文标题:react-pdf中实现预览pdf 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/xitong/1729505056a1203531.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论