React项目react-pdf使用

react项目中展示pdf

1.安装依赖

npm install react-pdf

2.封装一个根据url展示pdf的组件

javascript 复制代码
import { useState } from 'react'
import { Card } from "antd";
import style from './index.module.css'
import {message ,} from 'antd'
import PropTypes from 'prop-types';
import { Document, Page, pdfjs } from 'react-pdf'
import { DownOutlined, UpOutlined, MinusCircleOutlined, PlusCircleOutlined } from '@ant-design/icons';
import 'react-pdf/dist/esm/Page/AnnotationLayer.css'
import 'react-pdf/dist/esm/Page/TextLayer.css';
// 配置 PDF.js 的 worker 文件
pdfjs.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.js', import.meta.url).toString()
export default function PdfViewModal(props) {
    const [pageNumber, setPageNumber] = useState(1);
    const [numPages, setNumPages] = useState(1);
    const [scale, setScale] = useState(1.0);
    const onDocumentLoadSuccess = ({ numPages }) => {
        setNumPages(numPages)
    }
    //上一页
    const lastPage = () =>{
        if (pageNumber == 1) {
            message.info('已是第一页');
            return;
        }
        const page = pageNumber - 1;
        setPageNumber(page);
    }
    //下一页
    const nextPage = () =>{
        if (pageNumber == numPages) {
            message.info("已是最后一页");
            return;
        }
        const page = pageNumber + 1;
        setPageNumber(page);
    }
    //缩小
    const pageZoomOut = () => {
        if (scale <= 0.5) {
            message.info('已缩放至最小');
            return;
        }
        const newScale = scale - 0.1;
        setScale(newScale);
    }

    //放大
    const pageZoomIn = () => {
        if (scale >= 1) {
            message.info('已放大至最大');
            return;
        }
        const newScale = scale + 0.1;
        setScale(newScale);
    }

    return (
        <>
            <div className={style.setting_box}>
                <div className={style.setting_box_item} onClick={lastPage}><UpOutlined /></div>
                <div className={style.setting_box_item}>{pageNumber}/{numPages}</div>
                <div className={style.setting_box_item} onClick={nextPage}><DownOutlined /></div>
                <div className={style.setting_box_item} onClick={pageZoomIn}><PlusCircleOutlined /></div>
                <div className={style.setting_box_item} onClick={pageZoomOut}><MinusCircleOutlined /></div>
            </div>

            <Card className={style.pdf_box}>
            <Document 
                    file={new URL(props.url, import.meta.url).toString()}
                    onLoadSuccess={onDocumentLoadSuccess}
                >
                    <Page pageNumber={pageNumber} scale={scale} />
                </Document>
            </Card>
{/*             <div >

            </div> */}
        </>
    )
}

// 定义 propTypes 验证
PdfViewModal.propTypes = {
    url: PropTypes.string.isRequired,
};

// 设置默认 props
/* PdfViewModal.defaultProps = {
    url: '',
}; */

css样式

css 复制代码
.setting_box {
    display: flex;
    justify-content: space-between;
    height: 16px;
    align-items: center;
    background-color: #444;
    opacity: 0.5;
    border-radius: 20px;
    padding: 3px 8px;
    width: 125px;
    margin: 0 auto;
}

.setting_box_item {
    color: #ffffff;
}

.pdf_box {
    display: flex;
    justify-content: center;
    height: calc(100vh - 125px);
    margin-top: 10px;
    overflow-y: scroll;
}

3.调用组件

javascript 复制代码
  const items = [
    {
      key: '1',
      label: '课程内容',
      children: (
        <>
          {courseContent.pdfUrl && <PdfViewModal url={courseContent.pdfUrl}  />}
        </>
      ),
      icon: <FilePdfFilled />,
    },
    {
      key: '2',
      label: '课程视频',
      children: (
        <>
          {courseContent.videoUrl && <VideoViewModal url={courseContent.videoUrl} ref={voideChildRef} />}
        </>
      ),
      icon: <VideoCameraFilled />,
    },
    {
      key: '3',
      label: '知识图谱',
      children: (
        <>
          <ChartViewModal />
        </>
      ),
      icon: <InteractionFilled />,
    },
  ];

实现效果

相关推荐
亦暖筑序12 分钟前
AgentScope-Java 入门:完善 Vue 前端、发布 GitHub,并规划下一步
java·前端·vue.js
北斗落凡尘16 分钟前
Vue面试题
前端
程序员黑豆18 分钟前
鸿蒙应用开发之父子组件传参:@Param、@Event、@Once 装饰器详解与实战
前端·harmonyos
ClouGence18 分钟前
一个人录好的测试用例,团队怎么一起用?
前端·测试
无限压榨切图仔37 分钟前
从 Claude Code 切到 Codex:我用 Agent、Skills、MCP 做完了一个内容运营工具
前端·后端
濮水大叔41 分钟前
NestJS 与 CabloyJS 的 env/config 架构对比:从环境变量到实例级配置
前端·node.js·nestjs
成都渲染101云渲染666641 分钟前
Blender渲染时,纯CPU渲染的设置教程
前端·javascript·blender
董员外44 分钟前
RAG 系统进化论(一):纵览 RAG 的发展历程
前端·人工智能·后端
Gauss松鼠会1 小时前
【GaussDB】GaussDB锁阻塞源头查询
java·开发语言·前端·数据库·算法·gaussdb·经验总结
YHHLAI2 小时前
Vue 3 流式输出实战:从零掌握 LLM Streaming 与 SSE 协议
前端·javascript·vue.js