父页面变量必须挂到window上才能被子页面读取,否则子页通过parent.xxx访问会返回undefined;同源时应直接赋值window.xxx,跨域时须用postMessage通信并校验origin。
父页面变量必须挂到window上才能被子页面读取
子页面用parent.xxx访问不到,大概率是因为父页面变量没挂到window对象上。layui 的 iframe 子页和父页共享同源环境时,只能通过window这个顶层作用域通信——闭包里定义的let userdata = {...}或layui.use回调里声明的变量,子页根本看不见。
- ✅ 正确写法(父页面):
window.currentUser = { id: 1001, role: 'admin' }; - ❌ 错误写法(父页面):
layui.use(['table'], function() { const currentUser = {}; });→ 子页访问parent.currentUser返回undefined - ⚠️ 注意:Vue/React 项目中,状态默认不暴露,必须手动赋值给
window,比如window.appConfig = window.__APP_CONFIG__;
子页面访问前必须做存在性判断
iframe 加载快,父页面 JS 执行慢,子页一上来就console.log(parent.currentUser)很容易报Cannot read property 'currentUser' of undefined。别依赖$(document).ready(),它只管子页 DOM,不管父页逻辑是否就绪。
- 推荐写法(子页面):
if (window.parent && window.parent.currentUser) { console.log(window.parent.currentUser.id); } - 更稳妥的做法是监听
message事件,由父页在success回调里主动发数据:iframe.contentWindow.postMessage({ type: 'INIT_DATA', data: window.currentUser }, '*'); - 避免轮询
setTimeout,容易漏判或卡死;也别用parent.onload——iframe 没这属性
跨域时parent完全不可用,必须换postMessage
只要协议、域名、端口任一不同(比如localhost:8080开弹窗,iframe src 是localhost:3000),浏览器会直接拦截parent.xxx访问,并抛出Blocked a frame with origin ... from accessing a cross-origin frame错误。这时候任何parent、window.parent、top都无效。
- 父页面监听(需校验
event.origin):window.addEventListener('message', e => { if (e.origin !== 'http://your-iframe-domain.com') return; if (e.data.type === 'GET_USER') e.source.postMessage({ user: window.currentUser }, e.origin); }); - 子页面请求数据:
window.parent.postMessage({ type: 'GET_USER' }, 'http://your-parent-domain.com'); - ⚠️
'*'通配符在生产环境不安全,必须指定可信来源
layer.getChildFrame()不能用来读父页变量
这个 API 是 Layui 提供的用于操作子页面 DOM 的工具,返回的是子页面的body元素(2.8+)或 jQuery 对象(旧版),跟父页变量毫无关系。有人误以为layer.getChildFrame('html', index)能拿到父页上下文,实际调用.parent()或.ownerDocument.defaultView依然受限于同源策略,且在 sandbox 环境下大概率失败。
- ❌ 错误认知:
var parentWin = layer.getChildFrame('html', index).parent().get(0).ownerDocument.defaultView;→ 不可靠,也不该这么用 - ✅ 正确路径:变量通信只走
window(同源)或postMessage(跨域),其他绕路方式增加维护成本且易失效 - 真正卡住的地方,往往不是语法错,而是你忘了检查
window.currentUser在父页控制台是否真的存在











