iframe 提供了一种途径,让我们在一个页面中嵌入另一个页面。有些时候,我们希望两个窗口能够通信。每个窗口都有一个独立的 window 对象,窗口直接的相互通信就是通过 window 对象直接的相互引用来实现的。
重点在最后。
父窗口引用子窗口
frames 属性
父窗口中的 window 对象有一个 frames 的属性,通过它能够访问到其页面上的所有 iframe 的 window 对象。具体有两种方式:
window.frames[0] // 通过下标为数字
window.frames['iframeName'] // 通过器 iframe 的 name 属性。
值得说明的是,通过数字访问时,其数字并不是对应文档中 iframe 的位置顺序,而应该是按照其生成 DOM 节点的时间顺序。例如,文档加载完成后,通过 JavaScript 的方式生成了一个 iframe 并注册成了 body 的第一个子节点,那么它对应 window 对象并不是 window.frames[0]
, 而是 window.frames[window.frames.length - 1]
。
contentWindow 属性
通过 iframe 元素的 contentWindow 属性同样能够引用其 window 对象。
var iframe = document.getElementsByTagName('iframe')[0];
iframe.contentWindow;
子窗口引用父窗口
parent 属性
window.frames[0].parent === window; // true
最顶层的 window 对象的 parent 属性就是自身。
window.parent === window; // true,如果该 window 对象处于最顶层
top 属性
top 属性可以直接访问到最外层的 window 对象。如果存在如下的 iframe 嵌套:
window.frames[0].frames[0].frames[0].top === window;// true
安全限制
安全限制才是 iframe 之间相互应用的重点。安全限制并不会限制 window 对象之间的相互访问,但是如果要访问引用 window 对象的属性(或方法)时,处于安全策略,会限制两个页面必须是同域名(端口可以不同)。
如果两个页不在同一个域名下,那么:
var w = window.frames[0]; // OK
w.someMethod(); // 抛出一个错误
必须是同域名,意味着即使一个是另外一个子域也是不可以的。于是,这就造成了很大的局限性,因为我们经常嵌入来自其他子域的页面。这种情况下,我们可以通过设置文档的 domain 来实现。如果两个子域名分别是,a.example.com 和 b.example.com。那么我们只需要将两个页面的 domain 都设置为 example.com 就可以了。具体如下:
document.domain = 'example.com';
值得一提的是,document.domain 只能设置为当前域的父级域名或者祖先级,而且操作不可逆。如果网页的域名是 a.example.com,那么:
document.domain = 'c.a.example.com'; // 无效
document.domain = 'x.y.com'; // 无效
document.domain = 'example.com'; // 有效
document.domain = 'a.example.com'; // 无效,因为已经被设置为 'example.com'