子页面iframe跨域执行父页面定义的JS方法
问题需求:父页面与子页面iframe跨域嵌套,子页面要触发父页面所定义的js方法、父子页面的数据传递。
下文中会用到一些文件:父页面: parent.html;嵌在父页面的子iframe页面:child.html。
同域时 iframe 调用父页面的JS方法
在同域的情况下,子iframe页面可以很方便地直接调用父页面定义的JS方法:window.parent.fn(); 或者 window.top.fn();
- window.self: 当前窗口自身的引用
- window.parent: 上一级父窗口的引用
- window.top: 最顶层窗口的引用
当页面中不存在 iframe 嵌套时,则 window.self, window.parent, window.top 三者均是当前窗口自身的引用。比如,parent.html 和 child.html 均在 a.com 的同一域名下:
parent.html 代码
<iframe id="gameIframe" name="gameIframe" src="./game_iframe.html"></iframe> <!-- 或者 --> <iframe id="gameIframe" name="gameIframe" src="a.com/game_iframe.html"></iframe> <script> function sayHi () { alert('hi!'); } </script>
child.html 代码
window.parent.sayHi(); //或者 top.sayHi();
当 <iframe> 的链接与父页面不同域时,则子页面的 iframe 不能调用父页面定义的方法,会报错;如:parent.html 在 a.com 域名下,但子 iframe 的链接与 a.com 不同域:
<iframe id="gameIframe" name="gameIframe" src="b.com/game_iframe.html"></iframe> <!-- 此时在game_iframe.html页面调用父页面定义的方法,会报跨域错误 -->
实际上,跨域直接调用其它页面所定义的JS方法是做不到的。
postMessage 的发送与接收
Window.postMessage 是 HTML5 提供的一个跨域解决方案。基本的发送和接收使用如下。
(1)发送:otherWindow.postMessage(message, targetOrigin, [transfer]);
参数说明:
message: 将要发送到其他 window的数据;
otherWindow:其他窗口的一个引用,如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames;
targetOrigin: 通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串”*”(表示无限制)或者一个URI。
(2)接收:
window.addEventListener("message", function(event){ var data = event.data; // 判断域名 if(event.origin == 'http://192.168.1.237'){ //doSomething() } });
event 包含很多的信息,其中重要的几个分别是:
- event.data :传递过来的信息,也就是 postMessage 中发出的 message;
- event.origin: 发送信息页面的域名,包括协议和端口号。
跨域时 iframe 触发父页面的JS方法,数据双向传输
a.com 域名下的父页面 parent.html 定义了功能函数 sayHi();父页面 parent.html 中嵌套了子 iframe 页面 child.html(在域名b.com域名下) 。现在要实现:1)在child.html中引起触发、执行父页面定义的 sayHi()方法。2)在child.html中向父页面请求获取数据 uname 值。
基本思路:parent.html 和 child.html 2个页面分别设置 发送和接收,如下:
1) child.html代码:
<script type="text/javascript" src="sdk_child.js"></script> <script type="text/javascript"> // 1)触发父页面定义的方法 window.SDK.sayHi({msg: 'hi'}); // 2)向父页面请求获取数据 uname var uname = ''; window.SDK.getUname(); setTimeout(function(){ uname = window.SDK.uname; //doSomething(uname); }, 200); // 备注:发送请求后,需要延时接收返回的数据 </script>
2) child.html 中引入的js文件 sdk_child.js 代码:
;(function(){ var sdk = window.SDK || {}; sdk.uname = null; //发送 sdk.getUname = function(){ window.top.postMessage({ action: "getUname" }, "*")}; sdk.sayHi = function(info){ window.top.postMessage({ action: "sayHi", info: { msg: info.msg } }, "*")}; //接收 window.addEventListener("message", function(e){ var res = e; var action = res.data.action; var info = res.data.info; //判断域名 if(res.origin == 'a.com'){ switch (action) { case 'getUname' : sdk.uname = info; break; default : return } } }); //写入window window.SDK = sdk; })();
3) parent.html 中引入的js文件 sdk_parent.js代码:
;(function(){ var iframecont = document.getElementById('gameIframe').contentWindow; var sdk ={ getUname: function(){ var info = Tool.pareUrl(location.href); iframecont.postMessage({action: 'getUname', info: 'zhangsan'}, 'b.com'); }, sayHi: function(info){ alert(info.msg); }, }; //监听接收 window.addEventListener("message", function(e){ var res = e; var data = e.data; var info = e.data.info; if(true){ switch (data.action) { case 'sayHi' : sdk.sayHi(info); break; case 'getUname' : sdk.getUname(); break; default : return } } }); })();
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤