window.open

1. 参数

window.open常用来在新的window或新的tab页打开一个页面或文件(如图片、PDF等),它支持三个参数:

  1. strUrl:要打开的页面或资源的url地址。
  2. strWindowName:窗口的名字,用于后续对该窗口的引用,不是窗口的标题。
  3. strWindowFeatures:窗口的描述参数,如尺寸、位置、是否启用工具栏等。

该方法的返回值是新打开的窗口的引用,也就是新窗口的window对象。在遵循同源策略的情况下,可以直接通过该对象访问被打开的页面;即使在跨域的情况下,也可以通过window.postMessage向其发消息。

我们分别来解读这三个参数的用法:

(1). strUrl

打开的窗口中要加载的url,可以是一个HTML页面,或者其他任何浏览器能打开的资源文件。

要加载的url可以是同域的,也可以是跨域的。在跨域条件下,window.open满足和跨域的iframe一样的限制。从通信的角度来说,使用window.open打开窗口和在内嵌的iframe内打开页面是等价的,两者的差异更多是在于视觉效果的不同。

strUrl允许传入空值。此时第二个参数必须传入一个已打开的窗口的名字,从而获取这个窗口的引用:

// 打开一个窗口
let win = window.open('https://www.baidu.com', 'baidu');

// 通过窗口名获取上述窗口
let refWin = window.open('', 'baidu');

这样就可以在不打开新窗口的情况下获得窗口名为'baidu'的窗口的引用。

(2). strWindowName

该参数是被打开的窗口的名字,注意,它并不是窗口的标题。该参数只是一个窗口标识,用于以后通过它来找到对应的窗口的引用。

比如在上面的例子中,我们可以通过'baidu'这个名字来找到刚打开的百度的窗口,这样就不需要在全局变量中保存该窗口的引用了(它的代价不在于内存损耗,而在于对全局变量的维护)。

该参数除了支持普通的名字外,还支持和a标签一样的特殊关键字:_self_blank_parent_top,分别用于在当前窗口空白窗口父窗口顶级窗口中打开该窗口,具体的行为请参考a标签的target属性。

当传入了已经被使用过的窗口的名字时,不会新打开一个窗口,而是在该名字对应的窗口中打开,该窗口之前加载的内容会被替换。

// 在上述窗口打开csdn首页
window.open('https://csdn.net', 'baidu');

如果总是想打开新页面,可以给第二个参数传入'_blank'。不过此时如果需要引用这些窗口,需要即时保存窗口的引用。

(3). strWindowFeatures

窗口参数描述,字符串类型,各个参数由逗号隔开,参数之间以等号连接。比如下面的例子可以在距当前window左上角(10, 10)位置处打开一个宽度400像素,高度200像素的窗口:

window.open('https://www.baidu.com', 
  'baidu', 
  'top=10,left=10,width=400,height=200');

在这里插入图片描述
下面我们来看一些常用参数(图片来自mdn,由于不同浏览器的页面结构不一样,因此不是每个参数对每个浏览器都生效,具体请以实际效果为准。在Chrome中,基本只支持left、top、height和width,因此我们暂且仅介绍这四个参数):
在这里插入图片描述

  1. left,新窗口相对于当前浏览器页面左侧的距离。
  2. top,新窗口相对于浏览器页面顶部的位置,注意,不是相对于文档区域,而是整个浏览器页面。
  3. height,窗口内容区(即用户区,不包含工具栏、标签栏等)的高度,单位像素,最小值100。
  4. weight,窗口的宽度(包含滚动条),单位像素,最小值100。

其他参数如menubar、toolbar、location、personalbar等在Chrome中均不支持,如果需要在其他浏览器中启用,请参考mdn - window.open

2. 返回值

window.open返回的是对新打开的窗口的引用,即该窗口的window对象:

let refWin = window.open('https://www.baidu.com', 'baidu');
console.log(refWin);

在这里插入图片描述
不过这里引用到的window对象并不具备完整的DOM属性和方法,它仅仅提供了访问该页面的一些基本属性和方法,如图所示。

  1. blur(),手动移除窗口焦点的方法,refWin.blur()可使该窗口失去焦点。
  2. close(),关闭该窗口的方法。
  3. closed,标识该窗口是否已经被关闭。
  4. frames,新窗口内的frames
  5. length,新窗口内iframes的数量。
  6. location,新窗口window的location对象,用于访问窗口的地址信息。
  7. opener,该窗口的打开者。如我们在a页面通过window.open打开b页面,那么b页面的window.opener就是a页面的window。
  8. parent,该窗口的父窗口,由于是顶级窗口,因此它的值等于window自身。
  9. postMessage,通信接口,通过该方法可以实现向新窗口发送消息,优势是支持跨域。
  10. selfwindowtop,前两个均代指当前window,top指的是当前窗口所在页面的顶级窗口,由于自身已经是顶级窗口,因此top也是当前window。

3. 通信问题

使用window.open打开新窗口时,原窗口与新窗口之间是可以实现双向通信的。

在不跨域的情况下,可以直接访问页面内的任何全局变量、方法或DOM元素等。新窗口通过window.opener可以找到原窗口的window;而原窗口可以直接通过window.open的返回值访问新窗口,或者通过该窗口的名字找到该窗口,方法为:let ref = window.open('', 'windowName')

由于新窗口的加载是异步的,因此不能在调用window.open之后立即访问该窗口。可以在窗口的onload事件内访问新窗口:

let ref = window.open('/index.html');
ref.onload = function(){
  ... // 与新窗口通信
}

而在新页面中,可以直接通过window.opener访问原窗口,如:

// 查找原窗口内的p元素
let p = document.querySelectorAll('p', 
  window.opener.document);

在跨域的情况下,以上的方法会报错,因为会受到浏览器跨域安全策略的限制,此时就需要通过window.postMessage实现页面之间的通信。

在原窗口,可以通过对新窗口的引用调用postMessage:

let ref = window.open('https://www.baidu.com');
ref.postMessage(data, '*');

在新窗口内,同样通过window.opener访问原窗口:

window.opener.postMessage(data, '*');

在使用postMessage进行通信的时候存在一个小的兼容性问题,那就是IE8和IE9中的独立窗口之间通信时只能传递字符串,不支持其他数据类型,而在与页面内的iframe通信时没有这个问题。

总结

window.open本质上可以看做<a>标签的js版本,或者说是编码式地打开窗口。但它比<a>标签更加灵活,可以通过js实现与打开的页面之间的通信。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐