iframe间的参数传递

iframe,storage,postMessage

拭目以待 发布于

 iframe存在的时间已经很久了,有人会觉着过于老旧,也有人会觉着使用方便。iframe对于存在多个模块的项目来言,在隔离样式上的冲突、脚本间的干扰效果很明显,因为它们本身就不在一个scope。那么问题来了,隔离是隔离开了,相互间的传参如何解决。

一、通过更改iframe的src,并通过?id=1的形式进行传递:

<iframe src="" id="blog-main"></iframe>>

//通过document.getElementById获取frames
document.getElementById('blog-main').setAttribute('src', 'test.html?id=1');
//通过window.frames获取frames
window.frames['blog-main'].setAttribute('src', 'test.html?id=1')


这种方式简单粗暴,深受广大前端的喜爱。问题来了,不通过更改src如何解决?

二、通过localStorage的storage事件。

先来定义个场景: 在父级页面中触发一个button后,需要子iframe即时接收一个参数id。


<button id="button">save</button>
<iframe src="test2.html" width="100%" height="100%"></iframe>

//在父页面声明一个button的click事件:
document.getElementById('button').onclick = function(){
    localStorage.setItem('id', 1987);  //在事件中将id存储至localStorage中
};
//在iframe=>test2.html中声明storage事件
window.addEventListener("storage", function(e){ 
  /*
    event中存在的与storage相关的参数:
    ?storageArea: 表示存储类型(Session或Local)
    ?key:发生改变项的key
    ?oldValue: key的原值
    ?newValue: key的新值
    ?url*: key改变发生的URL
  */
  console.log(oldValue==> "+ e.oldValue + " newValue==>" + e.newValue);
}); 
//执行结果 oldValue==> null newValue==>1987


需要注意:

1、新增、删除必将触发storage事件,而在修改时,如果值并未发生变化,是不会触发storage事件;

2、 当前页面对localStorage进行操作,并不会触发当前页面的storage事件;

3、 storage事件只支持同域。也就是说,iframesrc如果指向的是非同域的地址,是不可能通过该方法进行实现的。如果有人实现了,记得留言交流下方法;


三、通过postMessage与message事件:

<button id="button2">save</button>
<iframe id="otherPage" src="http://localhost:3000/test3.html" width="100%" height="100%"></iframe>

//在父页面对button2绑定一个click事件
document.getElementById('button2').onclick = function(){
  window.frames['otherPage'].contentWindow.postMessage('hi, this is test1', 'http://localhost:3000');
};
//在iframe页面中绑定message事件进行接收
window.addEventListener("message", function( event ) {
    //获得父而面中传递的参数
    var _data = event.data;  // =>hi, this is test1
    //假设在id=otherPage的iframe中存在一个id为content的元素
    document.getElementById("content").innerHTML+=event.data+"<br/>"; 
    //当事件执行到这里时,通过在父而面中调用postMessage事件,对跨域下的iframe中的content元素进行了DOM操作
}, false );

需要注意:

1、通过这种方式不仅仅可以做到跨域参数传递,还可以通过在事件中的预设而跨域操作DOM;

2、如果使用jquery进行message事件绑定,data则需要使用event.originalEvent.data进行获取;

3、如果页面中只存在一个ID=otherPage的iframe时,window.frames[0]等同于window.frames['otherPage'].contentWindow。window.frames获取到iframes的window对象集,通过索引获取到对应的window对象;而window.frames['otherPage']是通过ID获取到iframe的DOM节点,所以需要调用contentWindow获取到所指向的window。

4、如果存在跨域,获取到的window对象是不完整的,如loction属性就是为空的。