postMessage是什么?
postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。
Html5中的postMessage解决跨域,跨窗口消息传递
postMessage的优点
- 两个跨域页面的消息传递
- 多窗口之间的消息传递
- 嵌套iframe的数据传递
postMessage()
postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。
postMessage(data,origin)方法接受两个参数
- data:要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果。
- origin:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以建参数设置为"*",这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。
例如:
// A页面 [http://a.com]
const data = document.getElementById('name').value;
window.frames[0].postMessage(data,'http://b.com');
在B页面监听message事件,获取传递过来的数据
// B页面 [http://b.com]
window.addEventListener('message', function(ev) {
// 当我们是父子窗口进行消息传递时,可以使用此判断,只接受父窗口传递来的消息,
if (ev.source !== window.parent) return;
var data = ev.data;
console.info('message from parent:', data);
}, false);
通过这样的一个传递和接受的过程可以实现一个完整的消息传递。不管A,B是否跨域,是否存在嵌套关系,都可以使用postMessage的方式实现消息传递。
MessageEvent的属性
- data:从源端传递来的message
- source:发送消息的窗口对象
- origin:发送消息窗口的源(协议+主机+端口号)
当我们只处理某些源发送过来的消息时,我们可以使用origin来做判断,只处理某一些源的message,这样方便过滤一些不必要的值。
解决问题
最近遇到一个问题,自己的代码【A_child】是通过Iframe的方式放在A系统中的,因为代码中需要A系统登录时的用户信息去获取资源,所以需要A系统中的cookie信息。目前的处理方式就是讲我的代码部署到A系统的服务器上,然后指定不同的端口,这样使用嵌入iframe的方式实现cookie共享。但是缺点就是每次更新代码都需要A系统的负责人去做更新。耗费了大量的人力和时间成本。
注意:相同的域名,不同的端口可以共享cookie信息。
最近为了减轻自己的工作负担,决定写一个中间层页面,放在A系统下,菜单的指向不变,只是在中间层的页面中在做一次iframe嵌套,并且在这个页面中将A系统中的cookie信息使用postMessage的方式发送给origin端。
注意:因为我自己代码进入时就需要带着用户信息请求表格数据,所以页面的所有操作必须在收到message后才进行。所以就有了下面的这个代码
window.addEventListener('message', (ev) => {
if (ev.source !== window.parent) return;
const data = ev.data;
...
...
...
Vue.prototype.userInfo = data;
new Vue({
el: '#app',
router,
store,
render: h => h(renderComponents),
});
}, false);
当然解决嵌套iframe跨域传值的问题,还有另外的两个方法。
- 使用hash值,将需要传递的值data放在iframe中src的hash中。
- 子页面传值给父页面,可以借助C页面【C和A必须时同域的】,A中嵌套B,B中嵌套C,B要想A传值,可以使用C作为一个事件BUS,B中的数据先传递给C,然后在通过C传递数据给A。【此方法筱筱没用过啊】,大概方法是这样的。
总结
html5新增的特性,postMessge主要是更方便的解决了多页面的消息传递,并且有效解决了跨域问题。使用起来更加的简单方便。不过根据自己的需求选择不同的处理方式。