React中如何实现window.open子窗口向父窗口传递数据?
跨窗口传token实现方案
直接用浏览器原生的postMessageAPI即可,不需要获取父组件的React实例引用,就能实现window.open打开的子窗口向父窗口传值,适配同源场景,安全无兼容问题。
父组件改造
你原来的父组件存在语法错误:不要在JSX return块内定义事件函数。正确逻辑需要提前注册message事件监听,校验消息来源后接收子窗口传回的token,组件卸载时记得移除监听避免内存泄漏:
import { useEffect, useCallback } from 'react'; function Parent() { // 接收子窗口消息的回调 const handleReceiveMessage = useCallback((event) => { // 同源校验,只接收当前域名下的消息,拦截未知来源请求,避免安全风险 if (event.origin !== window.location.origin) return; // 匹配SSO传token的消息类型 if (event.data?.type === 'SEND_SSO_TOKEN') { const receivedToken = event.data.payload; // 后续逻辑:存本地、发登录请求、更新组件状态都在这里写 console.log('父组件收到token:', receivedToken); } }, []); useEffect(() => { window.addEventListener('message', handleReceiveMessage); return () => { // 组件卸载时清理监听 window.removeEventListener('message', handleReceiveMessage); }; }, [handleReceiveMessage]); const openSSOWindow = () => { const left = (screen.width - 465) / 2; const top = (screen.height - 650) / 4; window.open( '/sso', 'SSOWindow', `resizable=yes,width=465,height=650,top=${top},left=${left}` ); }; return <button onClick={openSSOWindow}>打开SSO登录</button>; }
子组件改造
拿到token后,直接通过window.opener引用调用postMessage给父窗口发数据即可,加一层父窗口存在性判断,避免父窗口提前关闭导致JS报错:
function SSOPage() { const sendTokenToParent = () => { const token = '123-token-123'; // 替换成你实际获取到的token值 // 校验父窗口未被关闭 if (window.opener && !window.opener.closed) { window.opener.postMessage( { type: 'SEND_SSO_TOKEN', payload: token }, window.location.origin // 指定目标源为当前站点,做安全限制 ); // 传值完成后可以直接关闭当前SSO窗口 window.close(); } }; // 如果你是接口请求拿到的token,直接在接口成功回调里调用sendTokenToParent即可 return <div>SSO登录页</div>; }
注意事项
- 禁止直接给
window.opener挂载全局属性传值:容易造成全局变量污染,跨域场景下会直接抛出权限错误 - 必须做origin校验:不要省略
event.origin判断逻辑,避免恶意站点伪造消息窃取用户数据 - 及时清理事件监听:如果不手动移除message监听,重复挂载父组件会导致回调重复触发
内容的提问来源于stack exchange,提问作者xanderrybalov
相关产品推荐
相关产品推荐

