Next.js中react-pdf组件canvasRef绑定事件监听失败问题
React-PDF Page组件canvasRef绑定事件失效的解决方案
问题原因
- 组件挂载初期,PDF尚未完成渲染,
pdfRef.current还未指向真实的canvas元素,此时空依赖的useEffect无法成功添加事件监听器。 - 切换页码(
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
相关产品推荐
相关产品推荐

