父页面: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);
由于方案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的方法
来源: http://www.cnblogs.com/lycnblogs/p/7687255.html