Iframe父子窗口之間的跨域事件調用和傳值


實現方案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的方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM