我想在iframe上存档onClick事件,我使用该iframe来显示不同的发票pdf.

为此,我使用了filmix:

 const [filelist, setFilelist] = useState([])


  {filelist?.map((element, index) => (
                <div key={index} id={index + "_pdf"}
                    onMouseOver={(e) => handleOnMouseOver(e)}
                    onMouseOut={(e) => handleOnMouseOut(e)}
                >
                    {<iframe title="pdf_viewer" src={`${element.file_path_fe}`} width="100%" height="400em" />}
                </div>
            ))}

Now I've found this snippet:
https://codesandbox.io/p/sandbox/react-detect-mouse-click-over-iframe-708ys?file=%2Fsrc%2FApp.js%3A21%2C4
where clicks are detected via the blur effect. Since I use functional components, I have rewritten it this way:

useEffect(() => {
        ...

        // iframe clickable:
        // Focus the page
        window.focus();
        // Add listener to check when page is not focussed
        // (i.e. iframe is clicked into)
        window.addEventListener("blur", onblur);

        return () => {
            // Anything in here is fired on component unmount.
            // so clean up the window eventlistener
            window.removeEventListener("blur", onblur);
        }

        // remove onblur missing dependency warning
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, []);

以及功能:

const onblur = (e) => {
        if (state) {
            //window.focus();
            console.log(e);
        }
    };

    const handleOnMouseOver = (e) => {
        console.log("mouse in");
        setState({ iframeMouseOver: true });
    };

    const handleOnMouseOut = (e) => {
        console.log("mouse out");
        window.focus(); // Make sure to set focus back to page
        setState({ iframeMouseOver: false });
    };

它有效,但这并不完全是我想要的方式. 所以我的问题是:

  1. 它正确检测点击,但一次只能检测一次.之后,点击就会被忽略. 我曾try 重新聚焦窗口,希望在再次单击时重新触发模糊事件,但这不起作用. 我可以做些什么来存档和跟踪多次点击?
  2. 如果我点击当前Iframe,如何检测它? e.target仍然检测到它看起来的窗口. 由于我有多个pdf,所以我想获取我点击的当前pdf.
  3. 在useEffect挂钩中添加窗口. eventSYS是正确的方法吗?由于onblur功能存在警告.

Edit: 我有一个关于如何跟踪当前iframe的 idea ,我完全忘记了我有mouseOver事件. 我添加了一个变量:

const [pdfFrame, setPdfFrame] = useState([])

并在mouseOver事件中设置变量:

const handleOnMouseOver = (e) => {
    setPdfFrame([e.target])
    setState({ iframeMouseOver: true });
};

const handleOnMouseOut = (e) => {
    window.focus(); // Make sure to set focus back to page
    setPdfFrame([])
    setState({ iframeMouseOver: false });
};

但出于某种原因,模糊函数总是显示空变量,即使它是用正确的值重新渲染的:

console.log("Rendering with: ", pdfFrame);
const onblur = () => {
    if (state) {
        window.focus();
        console.log(pdfFrame);
    }
};

我认为这是正确的方法,但我在这里错过了一些东西.

Edit2: 感谢Lanre,我让它开始工作,这是完整的组件(没有不相关的东西):

import "./Matching.css"
import { useState, useEffect, React, useCallback } from 'react';

const Matching = () => {
    const [filelist, setFilelist] = useState([])
    const [state, setState] = useState([{ iframeMouseOver: false }])
    const [pdfFrame, setPdfFrame] = useState(null)

    const mandant = 2;


    useEffect(() => {
        /* here set the filelist, but only once on loading thus the []
           Create an file folder in public folder and add the pdf with this name(or any other name, and adjust the json)
           example:
        {
            "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))
    }, [])

    //var markedRows = []
    const onblur = useCallback(() => {
        if (state.iframeMouseOver) {
            setTimeout(() => {
                window.focus();
            }, 0);
        }
    }, [pdfFrame, state.iframeMouseOver]);

    // componentDidMount equivalent
    useEffect(() => {
        // iframe clickable:
        // Focus the page
        window.focus();
        // Add listener to check when page is not focussed
        // (i.e. iframe is clicked into)
        window.addEventListener("blur", onblur);

        //console.log(pdfFrame);
        return () => {
            // Anything in here is fired on component unmount.
            // so clean up the window eventlistener
            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(); // Make sure to set focus back to page
    };

    return (
        <div className="matching-wrapper">
            <div className="row">
                <div className="col-3">
                    {filelist?.map((element, index) => (
                        <div key={index} id={index + "_pdf"}
                            onMouseOver={(e) => handleOnMouseOver(e)}
                            onMouseOut={(e) => handleOnMouseOut(e)}
                        >
                            {<iframe title="pdf_viewer" src={`${element.file_path_fe}`} width="100%" height="400em" />}
                        </div>
                    ))}
                </div>
                <div className="col-2">
                    {/* other stuff not relevant to the question*/}
                </div>
                <div className="col-7">
                    {/* other stuff not relevant to the question*/}
                </div>
            </div>
        </div >
    );
};

export default Matching;

推荐答案

因此,我可以建议一些您可以try 的修复方法.查看您的代码,我认为您可以进行一些更改,例如:

  1. 以编程方式重新聚焦窗口,类似于:

const onblur = () => {
    if (state.iframeMouseOver) {
        console.log("Iframe was clicked");
        setTimeout(() => {
            window.focus();
        }, 0);
    }
};

  1. 您可以改进检测电流的方式.试试这个:

const [pdfFrame, setPdfFrame] = useState(null);

const handleOnMouseOver = (e) => {
    setPdfFrame(e.currentTarget.querySelector('iframe'));
    setState({ iframeMouseOver: true });
};

const handleOnMouseOut = (e) => {
    setPdfFrame(null);
    setState({ iframeMouseOver: false });
    window.focus();
};

  1. 您可以使用回调来正确确保onblur始终可以访问当前状态和props .

const onblur = useCallback(() => {
    if (state.iframeMouseOver) {
        console.log("Iframe clicked:", pdfFrame);
        setTimeout(() => {
            window.focus();
        }, 0);
    }
}, [pdfFrame, state.iframeMouseOver]);

useEffect(() => {
    window.addEventListener("blur", onblur);

    return () => {
        window.removeEventListener("blur", onblur);
    };
}, [onblur]);

如果这有帮助,请告诉我.干杯!

更新:@user3793935已使用工作解决方案更新了问题.

Javascript相关问答推荐

使用JavaScript重命名对象数组中的键

Phaser框架-将子对象附加到Actor

警告!合同执行期间遇到错误[执行已恢复](Base Layer 2)

if/else JavaScript中的条件行为

未捕获错误:在注销后重定向到/login页面时找不到匹配的路由

Msgraph用户邀请自定义邮箱模板

WebRTC关闭navigator. getUserMedia正确

如何粗体匹配的字母时输入搜索框使用javascript?

有没有可能使滑动img动画以更快的速度连续?

在JS中拖放:检测文件

我创建了一个创建对象的函数,我希望从该函数创建的对象具有唯一的键.我怎么能做到这一点?

覆盖加载器页面避免对页面上的元素进行操作

创建以键值对为有效负载的Redux Reducer时,基于键的类型检测

让chart.js饼图中的一个切片变厚?

在Vercel中部署Next.js项目时获取`ReferenceError:未定义文档`

使用RxJS from Event和@ViewChild vs KeyUp事件和RxJS主题更改输入字段值

如何通过Axios在GraphQL查询中发送数组

为什么NULL不能在构造函数的.Prototype中工作

为什么我的Navbar.css没有显示在本地主机页面上?

在每次重新加载页面时更改指针光标