如何向新窗口发送表单数据?window.postMessage监听无响应问题
问题排查与修复方案
接收端核心问题:监听逻辑完全倒置
你的接收组件里,useEffect中添加的receiveMessage监听逻辑搞反了——它要等收到消息后才去注册真正的消息监听,第一次发消息时,onMessageReceived还没绑定到窗口上,自然收不到任何消息。
修复后的接收端代码
const onMessageReceived = (event) => { // 必须先验证来源,规避跨域安全风险 if (event.origin !== `${env.NEXT_PUBLIC_URL}`) return; console.log(`Received message from parent window: ${event.data}`); // 还原JSON格式的数据 const parsedData = JSON.parse(event.data); console.log('解析后的数据:', parsedData); }; useEffect(() => { if(typeof window !== "undefined"){ // 页面加载完成直接注册消息监听 window.addEventListener('message', onMessageReceived); // 组件卸载时移除监听,防止内存泄漏 return () => { window.removeEventListener('message', onMessageReceived); }; } }, [])
发送端潜在问题:窗口加载事件处理不严谨
- 重复打开窗口时onload事件不触发:如果窗口已经打开过(
tab.current存在且未关闭),onload事件不会再次触发,导致sendDataToTab无法执行。 - onload赋值存在覆盖风险:使用
tab.current.onload = ...会直接覆盖之前的回调,不如addEventListener灵活可靠。
修复后的发送端代码
async function submit(...props) { let data = props[0]; if(status.current === "preview"){ openNewTab(); // 判断窗口是否已经加载完成 if (tab.current && tab.current.document.readyState === 'complete') { sendDataToTab(data); } else { const handleLoad = () => { sendDataToTab(data); tab.current.removeEventListener('load', handleLoad); }; // 用addEventListener绑定加载事件,避免覆盖 tab.current.addEventListener('load', handleLoad); } } } const openNewTab = () => { if (tab.current === null || tab.current.closed) { tab.current = window.open(`${env.NEXT_PUBLIC_URL}/employer/add-offer/preview`, '_blank'); } else { tab.current.focus(); // 窗口已存在时直接发送数据 sendDataToTab(data); } } const sendDataToTab = (data) => { if (tab.current === null || tab.current.closed) { console.log('No tab is currently open!'); } else { tab.current.postMessage(JSON.stringify(data), `${env.NEXT_PUBLIC_URL}`); } }
额外注意事项
- 始终严格验证
event.origin,防止恶意跨域消息注入; - 发送端用
JSON.stringify序列化数据,接收端记得用JSON.parse还原; - 发送前务必确认目标窗口未关闭,避免控制台报错。
内容的提问来源于stack exchange,提问作者Aleooo
相关产品推荐
相关产品推荐

