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


實現方案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);
     });
});


免責聲明!

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



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