zoukankan      html  css  js  c++  java
  • 子页面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 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    <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 代码:

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

    当 <iframe> 的链接与父页面不同域时,则子页面的 iframe 不能调用父页面定义的方法,会报错;
    如:parent.html 在 a.com 域名下,但子 iframe 的链接与 a.com 不同域:

    1
    2
    <iframe id="gameIframe" name="gameIframe" src="b.com/game_iframe.html"></iframe>
    <!-- 此时在game_iframe.html页面调用父页面定义的方法,会报跨域错误 -->

    实际上,跨域直接调用其它页面所定义的JS方法是做不到的。

    postMessage 的发送与接收

    Window.postMessage 是 HTML5 提供的一个跨域解决方案。基本的发送和接收使用如下:
    发送:
    otherWindow.postMessage(message, targetOrigin, [transfer]);
    参数说明:
    message: 将要发送到其他 window的数据;
    otherWindow:其他窗口的一个引用,如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames;
    targetOrigin: 通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串”*”(表示无限制)或者一个URI。

    接收:

    1
    2
    3
    4
    5
    6
    7
    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代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <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 代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    ;(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代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    ;(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
    }
    }
    });
    })();

    本文的探索,主要应用在h5游戏的JSSDK中。

  • 相关阅读:
    Windows消息机制
    inherited 为什么可以调用父类的private函数? [问题点数:100分,结帖人:h2plus0]
    C++Buidler6中需要注意的几个问题
    BGA封装芯片拆装全程纪实
    Delphi组件开发教程指南(四)组件生成过程(TWinControl)
    Delphi技巧集六 (等待执行完一个外部程序再执行另一个程序)
    C++ Builder高级应用开发指南
    干掉“Spirale”病毒
    完全看懂新世代x86指令集結構
    Delphi 组件撰写常问问题delphi 在整合环境中如何找出组件所产生的问题
  • 原文地址:https://www.cnblogs.com/sunshq/p/7976966.html
Copyright © 2011-2022 走看看