React多iframe(PDF预览)点击事件监听方案技术问询
React函数式组件中监听iframe点击事件的解决方案
在React函数式组件中通过iframe展示多份发票PDF时,需要实现iframe的点击事件监听。最初采用基于window blur事件的方案检测点击,但存在以下问题:
- 仅能检测单次点击,后续点击无法触发;
- 无法识别被点击的具体iframe实例;
- 在useEffect中绑定window事件监听器时出现依赖警告,实现方式存疑。
尝试通过mouseOver事件记录当前iframe,但blur函数无法获取更新后的状态值。最终借助useCallback等Hook解决了所有问题,完整可行的组件代码如下:
import "./Matching.css" import { useState, useEffect, useCallback } from 'react'; import axios from 'axios'; // 补充原代码缺失的axios导入 const Matching = () => { const [filelist, setFilelist] = useState([]) const [state, setState] = useState({ iframeMouseOver: false }) // 修正初始值为对象,更符合业务逻辑 const [pdfFrame, setPdfFrame] = useState(null) const mandant = 2; useEffect(() => { /* 仅在组件加载时获取文件列表,因此依赖项为空数组 需在public文件夹中创建对应目录并放入PDF文件,示例数据格式: { "file_path": "./view/public/files/2/8dc9e7a05ad84f0bd675624416f7c308.pdf", "file_path_fe": "./files/2/8dc9e7a05ad84f0bd675624416f7c308.pdf", "hash": "8dc9e7a05ad84f0bd675624416f7c308", "id": 1, "mandant": "2", "name": "Satzung.pdf", "org_name": "Satzung.pdf", "size": 126286, "type": "application/pdf" } */ axios.post("/select", { "table": "files", "columns": ["*"], "where": `where mandant = ${mandant}` }).then(res => setFilelist(res.data)) }, []) const onblur = useCallback(() => { if (state.iframeMouseOver) { setTimeout(() => { window.focus(); // 此处可添加点击iframe后的业务逻辑,比如打印当前选中的文件信息 console.log("点击了目标iframe:", pdfFrame); }, 0); } }, [pdfFrame, state.iframeMouseOver]); useEffect(() => { // 初始化时聚焦页面,确保blur事件能正确触发 window.focus(); // 添加window blur事件监听 window.addEventListener("blur", onblur); // 组件卸载时清理事件监听,避免内存泄漏 return () => { window.removeEventListener("blur", onblur); } }, [onblur]); const handleOnMouseOver = (e) => { setPdfFrame(e.currentTarget.querySelector('iframe')) setState({ iframeMouseOver: true }); }; const handleOnMouseOut = (e) => { setPdfFrame(null) setState({ iframeMouseOver: false }); window.focus(); // 鼠标移出时将焦点切回页面,确保后续blur事件正常触发 }; return ( <div className="matching-wrapper"> <div className="row"> <div className="col-3"> {filelist?.map((element, index) => ( <div key={element.id || index} id={`${index}_pdf`} onMouseOver={handleOnMouseOver} onMouseOut={handleOnMouseOut} > <iframe title={`pdf_viewer_${element.id || index}`} src={element.file_path_fe} width="100%" height="400em" /> </div> ))} </div> <div className="col-2"> {/* 其他无关内容 */} </div> <div className="col-7"> {/* 其他无关内容 */} </div> </div> </div > ); }; export default Matching;
关键解决点说明
- 用
useCallback包裹onblur函数:确保函数能捕获到最新的pdfFrame和state.iframeMouseOver状态值,同时消除useEffect的依赖警告。 - 通过
mouseOver/mouseOut追踪当前hover的iframe:鼠标悬停时记录目标iframe实例,移出时清空状态,结合blur事件判断是否点击了iframe。 - 每次blur后重新聚焦页面:保证后续点击iframe时能再次触发window blur事件,解决单次点击失效的问题。
内容的提问来源于stack exchange,提问作者user3793935
相关产品推荐
相关产品推荐

