认知一:只有通过window.open()打开的地址,才可以进行双向跨域通信
可以通过window.open打开任意地址,即使不同源,这两个地址间也可以互相postMessage
认知二:如果在页面内嵌套iframe,只有iframe的地址和页面地址同源,父元素才向iframe元素发送消息
有文章说,可以通过iframe.contentWindow获取到iframe嵌套页面的window,使用iframe.contentWindow.postMessage向iframe元素发送消息。但是因为同源策略,js仍只能获取到同一源的文档,因此,无法通过js操作iframe元素,也拿不到iframe.contentWindow
认知三:如果在页面内嵌套iframe,即使不同源,被iframe嵌套的页面也可以向父页面发送消息,但是前提是,父元素的url是明确的
假如被嵌套的页面是iframe.html,可以用过window.parent.postMessage('xxx', 父元素地址);父元素地址要是明确的,且要有端口号;比如http://xx.xxptcs.com:8080父元素可以通过
window.addEventListener('message',(data) => {})来接收消息;
认知三:如果要使用iframe这个元素,最好写在uselayout里面
使用postMessage遇到的坑
问题描述: 在父元素使用addEventListener接收message事件的时候,父元素接收到的事件次数要比iframe元素触发的多很多,而且次数会递增
当iframe第一次发送success事件时,window会接收到两次,第二次触发时,window会接收到四次,第三次
会接收到六次
解决过程
window上监听message事件有问题,那么监听其他事件有没有问题?所以使用click事件测试
window.addEventListener('click', () => { alert('click'); });
点击普通元素,正常,但是如果点击button元素,alert就会增加。再点击普通元素,alert的数量也会变成最新的。
思考: 因为使用的是window对象,所以所有元素触发click事件后,都会绑定到window上,翻看上面代码,有许多时机都会触发message事件,这些事件都会被注册到任务队列中,所以尝试去掉其他类型的postMessage
结果: 接收到的消息确实少了很多,但是每次还是会递增1
思考: 每次render的时候,window都会运行,是不是每次每次都会增加一个监听函数?测试效果如下
window.addEventListener('click', () => { alert('click'); }); window.addEventListener('click', () => { alert('click'); }); window.addEventListener('click', () => { alert('click'); });
addEventListener的特性就是可以为一个事件绑定多个事件处理函数,但onmessage指定的事件处理程序,被认为是元素的方法。一个属性只能对应一个方法
所以上面问题的解决办法是,将addEventListener换成onmessage