Files
mnote/design/pdf方案2.md
T

3.9 KiB
Raw Permalink Blame History

根据你的需求(PDF 内容精确引用到思维导图节点,且支持双向跳转),结合项目技术栈(Next.js + TypeScript),推荐以下 PDF 组件方案:

推荐组件:@react-pdf-viewer/core(搭配 @react-pdf-viewer/selection-mode 插件)

核心优势:

  1. 精确内容选取:支持页面级、文本片段级选择,可获取选中内容的页码、坐标、文本内容
  2. 双向链接能力:可生成带定位信息的锚点(如 #page=3&selection=xxx),实现思维导图点击跳转
  3. React 生态适配:完美兼容 Next.js 15 和 TypeScript,支持 SSR/SSG
  4. 轻量可扩展:核心包体积小,按需加载插件(如文本选择、搜索、缩放)

实现思路:

  1. PDF 查看器集成
// components/PDFViewer.tsx
import { Viewer, Worker } from '@react-pdf-viewer/core';
import { selectionModePlugin } from '@react-pdf-viewer/selection-mode';
import '@react-pdf-viewer/core/lib/styles/index.css';
import '@react-pdf-viewer/selection-mode/lib/styles/index.css';

const selectionMode = selectionModePlugin();
const { SelectionMode } = selectionMode;

interface PDFViewerProps {
  fileUrl: string;
  onSelect: (data: {
    text: string;
    pageNumber: number;
    position: { x: number; y: number };
  }) => void;
}

export default function PDFViewer({ fileUrl, onSelect }: PDFViewerProps) {
  return (
    <Worker workerUrl="https://unpkg.com/pdfjs-dist@3.4.120/build/pdf.worker.min.js">
      <SelectionMode
        onSelect={(args) => {
          if (args.selectionText) {
            onSelect({
              text: args.selectionText,
              pageNumber: args.pageIndex + 1, // 页码从1开始
              position: args.selectionRects[0]?.position || { x: 0, y: 0 },
            });
          }
        }}
      >
        <Viewer fileUrl={fileUrl} plugins={[selectionMode]} />
      </SelectionMode>
    </Worker>
  );
}
  1. 思维导图节点与 PDF 引用绑定
// 思维导图节点数据结构扩展
interface MindMapNode {
  id: string;
  text: string;
  pdfReference?: {
    fileId: string; // 关联的PDF文件ID
    pageNumber: number;
    text: string; // 引用的文本内容
    position?: { x: number; y: number }; // 可选:更精确的定位
  };
}

// 点击节点跳转PDF
const handleNodeClick = (node: MindMapNode) => {
  if (node.pdfReference) {
    // 导航到PDF查看页并定位
    router.push(`/documents/${node.pdfReference.fileId}?page=${node.pdfReference.pageNumber}`);
  }
};
  1. PDF 选择内容插入思维导图
// 在PDF查看页中使用
const PDFDocumentPage = ({ params }) => {
  const [mindMapNodes, setMindMapNodes] = useState<MindMapNode[]>([]);

  const handlePDFSelect = (data) => {
    // 创建新节点并关联PDF引用
    const newNode: MindMapNode = {
      id: uuidv4(),
      text: data.text.substring(0, 50) + '...', // 截断显示
      pdfReference: {
        fileId: params.id,
        pageNumber: data.pageNumber,
        text: data.text,
        position: data.position,
      },
    };
    setMindMapNodes([...mindMapNodes, newNode]);
  };

  return <PDFViewer fileUrl={pdfUrl} onSelect={handlePDFSelect} />;
};
  1. 双向跳转优化
  • 在 PDF 查看页加载时,通过 URL 参数自动定位到指定页:
    const { page } = useSearchParams();
    const defaultPage = page ? parseInt(page.toString()) : 1;
    // 传递defaultPage给Viewer组件
    
  • 思维导图节点显示引用标识(如 📄3 表示引用第3页),增强可视化关联

备选方案:

如果需要更强大的 PDF 处理能力(如 MinerU 提取后的结构化内容引用),可结合:

  • 后端MinerU 提取 PDF 时记录「文本块-页码」映射关系
  • 前端:通过 @react-pdf-viewer 定位到 MinerU 识别的文本块位置

该方案完全符合项目前后端分离架构,且能无缝集成到现有的思维导图(simple-mind-map)和文档系统中。