子页面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
代码:
1
2
3
4
5
6
7
8
|
<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
代码:
1
|
window.parent.sayHi(); //或者 top.sayHi();
|
当 <iframe>
的链接与父页面不同域时,则子页面的 iframe 不能调用父页面定义的方法,会报错;
如:parent.html
在 a.com
域名下,但子 iframe 的链接与 a.com
不同域:
1
2
|
<iframe id=“gameIframe” name=“gameIframe” src=“b.com/game_iframe.html”></iframe>
<!– 此时在game_iframe.html页面调用父页面定义的方法,会报跨域错误 –>
|
实际上,跨域直接调用其它页面所定义的JS方法是做不到的。
postMessage 的发送与接收
Window.postMessage 是 HTML5 提供的一个跨域解决方案。基本的发送和接收使用如下:
发送:otherWindow.postMessage(message, targetOrigin, [transfer]);
参数说明:message
: 将要发送到其他 window的数据;otherWindow
:其他窗口的一个引用,如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames;targetOrigin
: 通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串”*”(表示无限制)或者一个URI。
接收:
1
2
3
4
5
6
7
|
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
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<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
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
;(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
代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
;(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
}
}
});
})();
|
本文的探索,主要应用在h5游戏的JSSDK中。