You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js中react-pdf组件canvasRef绑定事件监听失败问题

React-PDF Page组件canvasRef绑定事件失效的解决方案

问题原因

  1. 组件挂载初期,PDF尚未完成渲染,pdfRef.current还未指向真实的canvas元素,此时空依赖的useEffect无法成功添加事件监听器。
  2. 切换页码(pageNumber变化)或PDF重新渲染时,react-pdf可能会重新创建canvas元素,原ref指向的旧元素被替换,导致之前绑定的事件失效。

可行解决方案

方案一:使用Ref回调函数(推荐)

通过ref回调函数,每次canvas元素更新时都重新绑定事件,确保事件始终作用于最新的canvas:

import React from "react";
import { Document, Page, pdfjs } from "react-pdf";
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
import styles from "../../pages/edit-pdf/editPdf.module.css";

const PDFViewer = () => {
  const [numPages, setNumPages] = React.useState<number>();
  const [pageNumber, setPageNumber] = React.useState<number>(1);

  // 用useCallback稳定函数引用,避免不必要的重复绑定
  const handleMouseDown = React.useCallback((event: MouseEvent) => {
    console.log("calling the function");
    const canvas = event.target as HTMLCanvasElement;
    const rect = canvas.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;
    console.log("Coordinate x: " + x, "Coordinate y: " + y);
  }, []);

  // Ref回调函数,每次canvas更新时重新绑定事件
  const handleCanvasRef = React.useCallback((canvas: HTMLCanvasElement | null) => {
    if (canvas) {
      // 先移除旧事件(防止重复绑定)
      canvas.removeEventListener("mousedown", handleMouseDown);
      canvas.addEventListener("mousedown", handleMouseDown);
    }
  }, [handleMouseDown]);

  function onDocumentLoadSuccess({ numPages }: { numPages: number }): void {
    setNumPages(numPages);
  }

  return (
    <div className={styles.pdf_provider_main}>
      <div className="container_main">
        <Document
          file={{ url: "nodedev.pdf" }}
          onLoadSuccess={onDocumentLoadSuccess}
        >
          <Page
            renderAnnotationLayer={false}
            renderTextLayer={false}
            pageNumber={pageNumber}
            className={styles.pdf_page}
            canvasRef={handleCanvasRef}
          ></Page>
        </Document>
        <p style={{ margin: "0px", padding: "10px", textAlign: "center" }}>
          Page {pageNumber} of {numPages}
        </p>
      </div>
    </div>
  );
};

export default PDFViewer;

方案二:调整useEffect依赖

通过监听pageNumber和handleMouseDown,确保每次页面切换或函数更新时,重新给最新的canvas绑定事件:

import React from "react";
import { Document, Page, pdfjs } from "react-pdf";
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
import styles from "../../pages/edit-pdf/editPdf.module.css";

const PDFViewer = () => {
  const [numPages, setNumPages] = React.useState<number>();
  const [pageNumber, setPageNumber] = React.useState<number>(1);
  const pdfRef = React.useRef<HTMLCanvasElement>(null);

  // 用useCallback稳定函数引用
  const handleMouseDown = React.useCallback((event: React.MouseEvent<HTMLCanvasElement, MouseEvent>) => {
    console.log("calling the function");
    if (pdfRef.current) {
      const rect = pdfRef.current.getBoundingClientRect();
      const x = event.clientX - rect.left;
      const y = event.clientY - rect.top;
      console.log("Coordinate x: " + x, "Coordinate y: " + y);
    }
  }, []);

  React.useEffect(() => {
    const canvasElement = pdfRef.current;
    if (canvasElement) {
      canvasElement.addEventListener("mousedown", handleMouseDown as any);
      return () => {
        canvasElement.removeEventListener("mousedown", handleMouseDown as any);
      };
    }
  }, [pageNumber, handleMouseDown]); // 监听页码变化和函数引用

  function onDocumentLoadSuccess({ numPages }: { numPages: number }): void {
    setNumPages(numPages);
  }

  return (
    <div className={styles.pdf_provider_main}>
      <div className="container_main">
        <Document
          file={{ url: "nodedev.pdf" }}
          onLoadSuccess={onDocumentLoadSuccess}
        >
          <Page
            renderAnnotationLayer={false}
            renderTextLayer={false}
            pageNumber={pageNumber}
            className={styles.pdf_page}
            canvasRef={pdfRef}
          ></Page>
        </Document>
        <p style={{ margin: "0px", padding: "10px", textAlign: "center" }}>
          Page {pageNumber} of {numPages}
        </p>
      </div>
    </div>
  );
};

export default PDFViewer;

内容的提问来源于stack exchange,提问作者dhruvin vaghasiya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 10:01:06