實現方案1:location.hash傳值
父頁面:parent.html(所在域:www.parent.com)
子頁面:child.html(所在域:www.child.com)
要實現父子頁面雙向的事件調用和傳值,需要多加一個代理頁面,主要用於子頁面調用父頁面的方法
代理頁面:proxy.html(所在域:www.parent.com)必須與父頁面在同域下
父頁面調用子頁面方法(即事件通過父頁面發起,在子頁面中執行):
父頁面中直接設置iframe的src中的hash值
parent.html:
1
2
|
var
frameurl =
"http://www.child.com/child.html"
document.getElementById(
"frameId"
).src=frameurl+
"#action="
+actionName+
"&data="
+dataJSONStr;
|
子頁面中設置定時器監聽hash的變化,監聽到后直接執行該方法
child.html:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
var
currentHash = location.hash;
setInterval(
function
(){
var
hash = location.hash.substring(1);
if
(currentHash!==hash){
var
action = ...;
var
data = ...;
childFuncClass[action](data);
}
},1);
|
同樣可以使用onhashchange事件監聽到
子頁面調用父頁面方法(事件通過子頁面發起,在父頁面中執行)
在子頁面child.html中添加一個iframe鏈接到上面所說的proxy.html,child.html中通過改變proxy.html的hash值,在proxy.html中監聽hash變化事件,監聽到以后直接調用parent.html中的方法(與父頁面調用子頁面方法一致)
proxy.html:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
var
currentHash = location.hash;
setInterval(
function
(){
var
hash = location.hash.substring(1);
if
(currentHash!==hash){
var
action = ...;
var
data = ...;
window.parent.parent[action](data);
}
},1);
|
存在問題:
data長度限制,在chrome,ff,safari等瀏覽器中hash長度限制有50K以上,但是在ie下最多2000左右的限制。
回調函數的處理
通常情況下父頁面在調用子頁面的方法時會有一些回調函數(函數是在parent.html中編寫和執行,但是需要child.html中的方法執行完成后再執行,有些情況下會需要child.html中執行的結果)
比如(通常情況下會做接口的封裝):
parent.html:
1
2
3
4
5
6
7
|
var
data={.....};
childFunc.func1(data,
function
(result){
//result即為child.html中執行func1后的結果值
});
|
child.html:
1
2
3
4
5
6
7
8
9
|
var
func1 =
function
(data,callback){
//對data的一些操作
var
result = ...;
callback&&callback(result);
}
|
如果出現這種情況的話parent.html中定義的匿名回調函數是不可能以字符串的形式傳遞到child.html中去的,並且也無法在child.html中再去執行父頁面的回調函數
解決方法:
在接口封裝的時候將回調函數保存下來,通過一個唯一的函數名傳遞到child.html中,child.html中的方法執行完成后將該函數名傳遞到proxy.html中執行該函數
以上面的func1為例
parent.html:
1
2
3
4
5
6
7
8
|
var
eventIndex=0;
childFunc.func1 =
function
(data,callback){
if
(
//callback是function類型){
//此時window是parent頁面的對象
window[
"myEvent"
+eventIndex] = callback;<br>
childIframe.hash=
"action=...&data=...&callback=myEvent"
+eventIndex;<br>
}
};
|
child.html:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
var
currentHash = location.hash;
setInterval(
function
(){
var
hash = location.hash.substring(1);
if
(currentHash!==hash){
var
action = ...;
var
data = ...;
var
callback=....;
//應該是myEvent+index
childFuncClass[action](data,
function
(result){
proxyIfram.src.hash=
"action="
+callback+
"&data="
+result;
});
}
},1);
|
proxy.html:
1
2
3
4
5
6
7
8
9
10
|
setInterval(
function
(){
if
(
//hash changed){
var
callback =
//hash.callback
var
callbackData =
//hash.callbackData
window.parent.parent[callback](callbackData);
}
},1);
|
實現方案2:window.postMessage方法
由於方案1中對ie兼容性有問題(所有ie版本,包括ie11和edge都存在這個問題),方案2使用postMessage方法,該方法理論上對數據量沒有限制(猜的),並且對ie可用
同樣是使用iframe嵌入,
parent.html
1
2
3
4
|
var
iframe = document.getElementById(
"childFrame"
).contentWindow;
var
msg = {data:parentData,action:childFunc,callback:
/*類似於上面的方法myEventIndex*/
}
var
childDomain =
"http://www.child.com"
iframe.postMessage(msg,childDomain);
|
1
2
3
4
5
6
|
window.addEventListener(
"message"
,
function
(obj){
var
data = obj.data;
var
action = data.action;
var
data = data.data;
parentFuncClass[action](data);
});
|
1
|
<br>
|
child.html
1
2
3
4
5
6
7
8
9
10
11
|
window.addEventListener(
"message"
,
function
(obj){
var
data = obj.data;
var
action = data.action;
var
data = data.data;
var
callback = data.callback;
childFuncClass[action](data,
function
(result){
var
d = {action:callback,data:result};
var
parentDomain=
"http://www.parent.com"
;
window.parent.postMessage(d,parentDomain);
});
});
|