跨窗口通信
一个窗口来自 baidu.com,另一个是 163.com,那么我们就不希望 baidu.com 的脚本可以阅读我们的邮件,这是由于“同源策略”限制了窗口之间的互相访问。
什么是同源?
如果两个URL具有相同的协议、相同的域名和端口,我们称它是同源的。例如以下几个示例:
- http://website.com
- http://website.com/
- http://website.com/my/page.html
那么以下就不能称是同源的
- http://www.website.com (www. 域名与其他不同)
- http://website.org (.org 域名与其他不同)
- https://website.com (协议与其他不同: https)
- http://website.com:8888(端口与其他不同:8888)
特殊情况
同源策略里面有一种特殊情况,如果窗口有相同的二级域名,像这样a.baidu.com和b.baidu.com,我们可以使用Javascript将document.domain设置为相同的二级域名baidu.com。那么此时这些窗体都将视为同源的
document.domain = 'baidu.com';
然后他们就可以无限制进行窗体之间的互动了,仅适用于具有相同二级域名的页面。
iframe
一方面,iframe就是一个标签,从另一方面来看,它是嵌套在窗体中的窗体。
嵌入的窗体有它单的的document和window对象,我们可以这样访问他们:
- iframe.contentWindow 是对
- iframe.contentDocument 是对
我们在访问嵌套的窗体时,浏览器时会检查iframe是否同源,如果不同源,会拒绝我们相互访问。举例如下:
![f4de5fd036cb1b2a39b48825631b28f7.png](https://i-blog.csdnimg.cn/blog_migrate/3dfb241a00088f420c3a70ce33329463.jpeg)
上述代码除了以下操作都会报错:
- 通过 iframe.contentWindow 获取内部窗口的 window
- 修改它的 location
备注:
iframe.onload 实际上与 iframe.contentWindow.onload 相同,当嵌入窗口内所有资源全部加载完后触发。 但是 iframe.onload 始终是可用的,然而 iframe.contentWindow.onload 需要满足同源策略。
对于同源,想怎么做就怎么做
![dafc67e0c05c82174832d3a8fe295169.png](https://i-blog.csdnimg.cn/blog_migrate/0c73fc0ed00375c834c586b210d2f2bd.jpeg)
等待iframe加载完成
我们咋子创建iframe的时候,它会立即有一个document,但是这个document与最终页面加载完成的document是不同的,看下面的代码:
![7b82d747ec15075e3fa72ba3c9052181.png](https://i-blog.csdnimg.cn/blog_migrate/dc35f6d8e6ba7abdba5ab958efd68fc8.jpeg)
对于初学者而言,这应该是一个不易察觉的陷阱。其实我们不能立即就用这个document对象,我们在它上面增加任何事件都会被忽略掉。但是如果我们希望更早的时候就能使用它,在同源情况下可以这样,当然如果你有更好的办法,欢迎在评论区留言告诉我。
![1bcd096220c0f425b8e3d7726f94f5b7.png](https://i-blog.csdnimg.cn/blog_migrate/2e0872a02a33a6262592ff5ee620f413.jpeg)
window.frames
获取
- 通过索引window.frames[0]
- 通过名称获取:window.frames.myiframe(获取 name="myiframe" 的 iframe 窗口)
示例:
![6cd5cc16ff05ff3ebbcfbb14753e6e10.png](https://i-blog.csdnimg.cn/blog_migrate/dec775bb4623fb1efbca8b21ae8b3616.jpeg)
一个 iframe 内如果嵌套了其他的 iframe,相应的 window 对象会也形成嵌套结构,可以通过以下方式获取
- window.frames(子窗口的集合(用于嵌套的 iframe))。
- window.parent ( 对"父"(外部)窗口的引用)。
- window.top(对最顶级父窗口的引用)。
举例
![a6c6dfdc82d449b93ad474d673eb4ba0.png](https://i-blog.csdnimg.cn/blog_migrate/d37301b8210bad016dcc79e20ba87457.jpeg)
检测top属性,来确定是否时在iframe下打开的
![43d2bcbe33ecd6a40a8ccd31106c5cf3.png](https://i-blog.csdnimg.cn/blog_migrate/3753a99ca6cdad83b681954a332f8eaf.jpeg)
sandbox 属性
sandbox属性可以在iframe中禁止一些特定的操作,防止不被信任的代码执行,有关于此属性的应用可以自行了解下,以下时它的一些属性
- allow-top-navigation
允许 iframe 修改父窗口的地址。
- allow-forms
允许在 iframe 内提交表单。
- allow-scripts
允许在 iframe 内运行脚本。
- allow-popups
允许来自 iframe 的 window.open 弹出窗口
备注:
"sandbox" 属性的目的是为了添加更多限制。它不能移除这些限制,尤其是当 iframe 是非同源时,更不能放松同源策略。
跨窗口通信
通过 postMessage 这个接口,我们可以在不同源的窗口内进行通信
- postMessage
看代码:
![ec8cf918601a4b2d7e915e4dfa1f9529.png](https://i-blog.csdnimg.cn/blog_migrate/2f53f0fc7e154f65b45e3b99ad1c5abc.jpeg)
只有当 win 内的站点是 http://example.com这个源时才会接受消息,如果不想有这样的限制,那么我们可以这样
![918d3f9ea359dc7a246f620c791a9111.png](https://i-blog.csdnimg.cn/blog_migrate/d8560238ac6aa12a3ae35d8a919de8b3.jpeg)
- onmessage
为了接收消息,目标窗口应该在 message 事件上增加一个处理函数。当 postMessage 被调用时这个事件会被触发(并且 targetOrigin 检查成功),举例
![33fe3ac9009c1e01a3ef26699e385abb.png](https://i-blog.csdnimg.cn/blog_migrate/8731a296eb624453e9523ce19c744d61.jpeg)
总结一下
本文简单的介绍了下web开发中的跨窗体通信,降到了一些需要注意的地方,如果觉得本文对你有帮助,请麻烦点个关注吧!谢谢!