概述
弹窗
- 弹窗是一个独立的窗口,具有自己的独立 JavaScript 环境。因此,使用弹窗打开一个不信任的第三方网站是安全的
 - 弹窗可以导航(修改 URL),并将消息发送到 opener 窗口
 - 如果弹窗是在用户触发的事件处理程序(如 
onclick)之外调用的,大多数浏览器都会阻止此类弹窗 
打开新的弹窗
语法:
window.open(url, name, param)默认情况下,浏览器会打开一个新标签页,但如果提供了窗口大小,那么浏览器将打开一个弹窗
url:要在新窗口加载的 URLname:新窗口的名称,每个窗口都有一个window.name,可以指定哪个窗口用于弹窗,如果已经有一个这样名字的窗口,将在该窗口打开给定的 URL,否则会打开一个新窗口param:新窗口的配置字符串,它包括设置,用逗号分隔,参数之间不能有空格,例如:width=200,height=100(多屏环境下,某些参数会失效)- 位置 
left/top(数字):屏幕上窗口的左上角的坐标。这有一个限制:不能将新窗口置于屏幕外width/height(数字):新窗口的宽度和高度。宽度/高度的最小值是有限制的,因此不可能创建一个不可见的窗口
 - 窗口功能(参数值均为 
yes/no)menubar:显示或隐藏新窗口的浏览器菜单toolbar:显示或隐藏新窗口的浏览器导航栏(后退,前进,重新加载等)location:显示或隐藏新窗口的 URL 字段。Firefox 和 IE 浏览器不允许默认隐藏它status:显示或隐藏状态栏。同样,大多数浏览器都强制显示它resizable:允许禁用新窗口大小调整。不建议使用scrollbars:允许禁用新窗口的滚动条。不建议使用
 
- 位置 
 
参数规则
- 如果 
open调用中没有第三个参数,或者它是空的,则使用默认的窗口参数 - 如果这里有一个参数字符串,但是某些 
yes/no功能被省略了,那么被省略的功能则被默认值为no。因此,如果你指定参数,请确保将所有必需的功能明确设置为yes - 如果参数中没有 
left/top,那么浏览器会尝试在最后打开的窗口附近打开一个新窗口 - 如果没有 
width/height,那么新窗口的大小将与上次打开的窗口大小相同 
操作新窗口
如果主窗口和弹窗同源,那么它们可以彼此自由地读取和修改。否则,它们可以更改彼此的地址(location),交换消息
let newWin = open('http://localhost/test.html', 'test', params);
// 重写新窗口内容
newWin.document.write("Hello, world!");
// 获取新窗口内容
newWin.onload = function(){
  console.log(newWin.document.body.innerHTML)
}从弹窗访问窗口
// 弹窗窗口通过 window.opener 获取父窗口对象
window.opener.document.body.innerHTML = '<h1>新页面修改</h1>'关闭窗口
window.closed:检查窗口是否被关闭window.close():关闭窗口- 适用于任何 
window,如果window不是通过window.open()创建的,那么大多数浏览器都会忽略window.close()。因此,close()只对弹窗起作用 
- 适用于任何 
 
调整窗口
为了防止滥用,浏览器通常会阻止这些方法。它们仅在我们打开的,没有其他选项卡的弹窗中能够可靠地工作
JavaScript 无法最小化或者最大化一个窗口。这些操作系统级别的功能对于前端开发者而言是隐藏的
移动或者调整大小的方法不适用于最小化/最大化的窗口
win.moveBy(x,y):将窗口相对于当前位置向右移动x像素,并向下移动y像素。允许负值(向上/向左移动)win.moveTo(x,y):将窗口移动到屏幕上的坐标(x,y)处win.resizeBy(width,height):根据给定的相对于当前大小的width/height调整窗口大小。允许负值win.resizeTo(width,height):将窗口调整为给定的大小
跨窗口通信
同源
如果两个 URL 具有相同的协议,域和端口,则称它们是“同源”的
如果有对另外一个窗口(例如:一个使用
window.open创建的弹窗,或者一个窗口中的iframe)的引用,并且该窗口是同源的,则具有对该窗口的全部访问权限否则,如果该窗口不是同源的,则无法访问该窗口中的内容:变量,文档,任何东西。
- 唯一的例外是 
location:可以修改它(进而重定向用户)。但是无法读取location(因此,无法看到用户当前所处的位置,也就不会泄漏任何信息) 
- 唯一的例外是 
 
iframe
承载了一个单独的嵌入的窗口,它具有自己的
document和window当访问嵌入的窗口中的东西时,浏览器会检查
iframe是否具有相同的源。如果不是,则会拒绝访问(对location进行写入是一个例外,它是会被允许的)
iframe.contentWindow:获取<iframe>中的windowiframe.contentDocument:获取<iframe>中的document,是iframe.contentWindow.document的简写形式- 一个 iframe 内可能嵌套了其他的 iframe。相应的 
window对象会形成一个层次结构window.frames:“子”窗口的集合(用于嵌套的 iframe)window.parent:对“父”(外部)窗口的引用window.top:对最顶级父窗口的引用
 
<iframe src="https://localhost/test.html" id="iframe"></iframe>
<script>
  iframe.onload = function() {
    // 获取对内部 window 的引用
    let iframeWindow = iframe.contentWindow; // OK
    try {
      // 无法获取其中的文档
      let doc = iframe.contentDocument; // ERROR
    } catch(e) {
      alert(e); // Security Error(另一个源)
    }
    // 并且无法读取 iframe 中页面的 URL
    try {
      // 无法从 location 对象中读取 URL
      let href = iframe.contentWindow.location.href; // ERROR
    } catch(e) {
      alert(e); // Security Error
    }
    // 可以写入 location(所以,在 iframe 中加载了其他内容)!
    iframe.contentWindow.location = '/'; // OK
    iframe.onload = null; // 清空处理程序,在 location 更改后不要再运行它
  };
</script>二级域名下的通信
需要再每个窗口中添加如下代码,使浏览器忽略该差异,使得它们可以被作为“同源”的来对待,以便进行跨窗口通信
// 已弃用,但仍有效
document.domain = 'http://localhost';postMessage
允许窗口之间相互通信,无论它们来自什么源,是解决“同源”策略的方式之一
- 发送方语法:
otherWin.postMessage(data, targetOrigin)(otherWin:接收方 windowdata:要发送的数据。可以是任何对象,IE 浏览器只支持字符串,因此需要对复杂的对象调用JSON.stringify方法进行处理,以支持该浏览器targetOrigin:接收方的源,以便只有来自给定的源的窗口才能获得该消息- 如果不做这个检查,可以将 
targetOrigin设置为* 
- 如果不做这个检查,可以将 
 
 - 接收方使用 
onmessage事件接收,参数event相关参数如下event.data:传递过来的数据event.prigin:发送方的源event.source:对发送方窗口的引用(发送方 window)
 
<!-- index.html 发送方 http://127.0.0.1:56082 -->
<script>
	newWin = open('http://127.0.0.1:64361', 'test', params);
  setInterval(function() {
    newWin.postMessage(JSON.stringify({
      a: 1,
      b: 2
    }), 'http://127.0.0.1:64361')
  }, 2000)
</script>
<!-- test.html 接收方 http://127.0.0.1:64361 -->
<script>
  window.addEventListener("message", function(event) {
    console.log(event)
    console.log(event.data)
    // 可以使用 event.source.postMessage(...) 向回发送消息
    // event.origin http://127.0.0.1:56082/
    event.source.postMessage('反向发送信息', event.origin)
  });
</script>