zoukankan      html  css  js  c++  java
  • 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);
        });
    });
  • 相关阅读:
    [组合][DP]luogu P3643 [APIO2016]划艇
    [倍增]luogu P4155 [SCOI2015]国旗计划
    [并查集][线段树]luogu P3273 [SCOI2011]棘手的操作
    pytest警告DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3,and in 3.9 it will stop working
    docker-compose5分钟搭建wordpress博客网站
    Docker安装入门
    Windows10安装wget命令
    CRC (Cyclic Redundancy Check)
    Linux学习笔记
    Linux学习笔记
  • 原文地址:https://www.cnblogs.com/ylyw/p/7687726.html
Copyright © 2011-2022 走看看