實現方案1:location.hash傳值 父頁面:parent.html(所在域:www.parent.com) 子頁面:child.html(所在域:www.child.com) 要實現父子頁面雙向的事件調用和傳值,需要多加一個代理頁面,主要用於子頁面調用父頁面的方法 代理頁面:proxy.ht ...
實現方案1:location.hash傳值
父頁面:parent.html(所在域:www.parent.com)
子頁面:child.html(所在域:www.child.com)
要實現父子頁面雙向的事件調用和傳值,需要多加一個代理頁面,主要用於子頁面調用父頁面的方法
代理頁面:proxy.html(所在域:www.parent.com)必須與父頁面在同域下
父頁面調用子頁面方法(即事件通過父頁面發起,在子頁面中執行):
父頁面中直接設置iframe的src中的hash值
parent.html:
var frameurl = "http://www.child.com/child.html" document.getElementById("frameId").src=frameurl+"#action="+actionName+"&data="+dataJSONStr;
子頁面中設置定時器監聽hash的變化,監聽到後直接執行該方法
child.html:
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:
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:
var data={.....}; childFunc.func1(data,function(result){ //result即為child.html中執行func1後的結果值 });
child.html:
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:
var eventIndex=0; childFunc.func1 = function(data,callback){ if(//callback是function類型){ //此時window是parent頁面的對象 window["myEvent"+eventIndex] = callback;
childIframe.hash="action=...&data=...&callback=myEvent"+eventIndex;
} };
child.html:
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:
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
var iframe = document.getElementById("childFrame").contentWindow; var msg = {data:parentData,action:childFunc,callback:/*類似於上面的方法myEventIndex*/} var childDomain = "http://www.child.com" iframe.postMessage(msg,childDomain);
window.addEventListener("message",function(obj){ var data = obj.data; var action = data.action; var data = data.data; parentFuncClass[action](data); });
child.html
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); }); });
真的是坑啊,把方案1中的坑都走過後才找到方案2的方法