子頁面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 代碼

<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 代碼

window.parent.sayHi(); //或者 top.sayHi();

 

當 <iframe> 的鏈接與父頁面不同域時,則子頁面的 iframe 不能調用父頁面定義的方法,會報錯;如:parent.html 在 a.com 域名下,但子 iframe 的鏈接與 a.com 不同域:

<iframe id="gameIframe" name="gameIframe" src="b.com/game_iframe.html"></iframe>
<!-- 此時在game_iframe.html頁面調用父頁面定義的方法,會報跨域錯誤 -->

 

實際上,跨域直接調用其它頁面所定義的JS方法是做不到的。

postMessage 的發送與接收

Window.postMessage 是 HTML5 提供的一個跨域解決方案。基本的發送和接收使用如下。

(1)發送:otherWindow.postMessage(message, targetOrigin, [transfer]);

  參數說明:

    message: 將要發送到其他 window的數據;

    otherWindow:其他窗口的一個引用,如iframe的contentWindow屬性、執行window.open返回的窗口對象、或者是命名過或數值索引的window.frames;

    targetOrigin: 通過窗口的origin屬性來指定哪些窗口能接收到消息事件,其值可以是字符串”*”(表示無限制)或者一個URI。

(2)接收:

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代碼:

<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 代碼:

;(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代碼:

;(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
            }
        }
    });
})();

 

 


 


免責聲明!

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



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