前端 iframe 通讯,这才是更优解(附完整 Demo)
前端 iframe 通讯这才是更优解附完整 Demo一句话总结别再瞎用 window.xxx 了老老实实用 postMessage安全又清晰。一、为什么我一开始就踩坑了之前做一个后台系统需要在主页面里嵌一个 iframe你懂的微前端、第三方系统、历史包袱…。需求很简单 父页面给 iframe 传参数 iframe 再把结果回传给父页面我一开始的骚操作是这样的// 父页面iframe.contentWindow.someMethod(data)然后 iframe 里window.someMethodfunction(data){console.log(data)}看起来很合理对吧结果❌ 跨域直接炸经典老朋友❌ iframe 没加载完直接 undefined❌ 调试起来像在抓鬼真的玄学当时我就一个感受这玩意不靠谱后来老老实实用了postMessage世界清净了。二、iframe 通讯的本质到底是什么先说人话版本 iframe 本质就是一个“独立窗口” 不同窗口之间通信必须走浏览器提供的“安全通道”这个“官方通道”就是window.postMessage它解决了两个核心问题跨域通信安全隔离不会随便乱访问变量三、核心原理postMessage 到底干了啥简单理解就是 A 窗口发消息 B 窗口监听消息就像 WebSocket 的迷你版但只限浏览器内部四、最基础 Demo父 → iframe1️⃣ 父页面iframeidchildsrchttp://localhost:3001/iframescriptconstiframedocument.getElementById(child)iframe.onload(){iframe.contentWindow.postMessage({type:INIT,data:{name:张三}},http://localhost:3001)}/script2️⃣ iframe 页面window.addEventListener(message,(event){console.log(收到消息,event.data)if(event.data.typeINIT){console.log(初始化数据,event.data.data)}})五、iframe → 父页面// iframe 页面window.parent.postMessage({type:SUCCESS,data:操作完成},http://localhost:3000)父页面监听window.addEventListener(message,(event){console.log(子页面返回,event.data)})六、升级版封装一个通信工具推荐说实话直接用postMessage还是有点“原始”。我后来自己封了一层踩坑之后的觉悟工具函数通用版// messenger.jsexportfunctioncreateMessenger(targetWindow,targetOrigin){return{send(type,data){targetWindow.postMessage({type,data},targetOrigin)},listen(type,handler){functionlistener(event){if(event.origin!targetOrigin)returnif(event.data.typetype){handler(event.data.data)}}window.addEventListener(message,listener)return(){window.removeEventListener(message,listener)}}}}父页面用法constiframedocument.getElementById(child)constmessengercreateMessenger(iframe.contentWindow,http://localhost:3001)iframe.onload(){messenger.send(INIT,{id:123})}messenger.listen(SUCCESS,(data){console.log(收到返回,data)})iframe 用法constmessengercreateMessenger(window.parent,http://localhost:3000)messenger.listen(INIT,(data){console.log(初始化,data)messenger.send(SUCCESS,OK)})七、结合 WebGIS 实战OpenLayers 场景真实项目里我是这么用的 主页面是业务系统 iframe 里跑的是 OpenLayers 地图父页面控制地图定位messenger.send(MAP_FLY,{lon:116.39,lat:39.9})iframe地图页面messenger.listen(MAP_FLY,({lon,lat}){map.getView().animate({center:ol.proj.fromLonLat([lon,lat]),zoom:12})})地图点击 → 回传父页面map.on(click,(e){constcoordol.proj.toLonLat(e.coordinate)messenger.send(MAP_CLICK,{lon:coord[0],lat:coord[1]})})八、那些年我踩过的坑血泪版1️⃣ 忘记校验 origin非常危险// ❌ 错误示范window.addEventListener(message,(event){console.log(event.data)}) 任何网站都能给你发消息正确做法if(event.origin!http://localhost:3001)return2️⃣ iframe 还没加载就发消息// ❌ 很容易翻车iframe.contentWindow.postMessage(...) 必须等iframe.onload(){...}3️⃣ targetOrigin 写成 *postMessage(data,*) 能跑但不安全上线直接背锅4️⃣ 事件监听不销毁内存泄漏 单页应用尤其容易炸九、进阶建议稍微卷一点点如果你项目复杂一点可以考虑封装成事件总线支持 request / response类似 RPC加消息 ID 做回调加超时机制十、总结说句实在话 iframe 通讯不难难的是“别乱搞”你只要记住三点只用 postMessage一定校验 origin封一层别到处散着写很多人写 iframe 通讯像在“拼多多砍一刀”东一刀西一刀最后谁都看不懂。但你一旦把通信当成“协议”来设计 整个系统会清爽很多最后送一句我踩坑后的感悟能抽象就别硬写能规范就别乱来。不然未来的你一定会回来骂现在的你 如果这篇文章对你有帮助欢迎点赞 收藏 ⭐ 关注 完结撒花✿✿ヽ(°▽°)ノ✿