文章简介
本篇文章为【JavaScript 漫游】专栏的第 030 篇文章,记录了浏览器模型中 window 对象的相关知识点。
window 对象概述
浏览器里面,window
对象(注意,w
为小写)指当前的浏览器窗口。它也是当前页面的顶层对象,即最高一层的对象,所有其他对象都是它的下属。一个变量如果未声明,那么默认就是顶层对象的属性。
a = 1;
window.a // 1
window 对象的属性
这里介绍 window 对象常用的属性,包括:
window.closed
window.screenX
和window.screenY
window.innerHeight
和window.innerWidth
window.outerHeight
和window.outerWidth
window.scrollX
和window.scrollY
window.pageXOffset
和window.pageYOffset
window.locationbar
window.menubar
window.scrollbars
window.toolbar
window.statusbar
window.personalbar
window.document
window.location
window.navigator
window.history
window.localStorage
window.sessionStorage
window.console
window.screen
window.closed
返回一个布尔值,表示窗口是否关闭。
window.scrollX
和 window.scrollY
返回浏览器窗口左上角相对于当前屏幕左上角的水平距离和垂直距离(单位像素)。这两个属性只读。
window.innerHeight
和 window.innerWidth
返回网页在当前窗口中可见部分的高度和宽度,即“视口”(viewport)的大小(单位像素)。这两个属性只读。
注意,这两个属性值包括滚动条的高度和宽度。
window.outerHeight
和 window.outerWidth
返回浏览器窗口的高度和宽度,包括浏览器菜单和边框(单位像素)。这两个属性只读。
window.scrollX
和 window.scrollY
window.scrollX
属性返回页面的水平滚动距离,window.scrollY
属性返回页面的垂直滚动距离,单位都为像素。这两个属性只读。
注意,这两个属性的返回值不是整数,而是双精度浮点数。如果页面没有滚动,它们的值就是 0
。
window.pageXOffset
和 window.pageYOffset
window.scrollX
和 window.scrollY
的别名。
window.locationbar
地址栏对象
window.menubar
菜单栏对象
window.scrollbars
窗口的滚动条对象
window.toolbar
工具栏对象
window.statusbar
状态栏对象
window.personalbar
用户安装的个人工具栏对象
window.document
指向 document
对象,这个属性有同源限制。只有来自同源的脚本才能读取这个属性
window.location
指向 Location 对象,用于获取当前窗口的 URL 信息。它等同于document.location
属性
window.navigator
指向 Navigator 对象,用于获取环境信息
window.history
指向 History 对象,表示浏览器的浏览历史
window.localStorage
指向本地储存的 localStorage 数据
window.sessionStorage
指向本地储存的 sessionStorage 数据
window.console
指向 console
对象,用于操作控制台
window.screen
指向 Screen
对象,表示屏幕信息
window 对象的方法
window 对象的常用方法有如下:
window.alert()
、window.prompt()
和window.confirm()
window.open()
、window.close()
和window.stop()
window.scrollTo()
、window.scroll()
和window.scrollBy()
window.print()
window.focus()
和window.blur()
window.requestAnimationFrame()
window.requestIdleCallback()
window.alert()
、window.prompt()
和 window.confirm()
window.alert()
、window.prompt()
、window.confirm()
都是浏览器与用户互动的全局方法。它们会弹出不同的对话框,要求用户做出回应。注意,这三个方法弹出的对话框,都是浏览器统一规定的式样,无法定制。
window.alert()
方法弹出的对话框,只有一个“确定”按钮,往往用来通知用户某些信息。
alert('本条提示\n分成两行');
window.prompt()
方法弹出的对话框,提示文字的下方,还有一个输入框,要求用户输入信息,并有“确定”和“取消”两个按钮。它往往用来获取用户输入的数据。
var result = prompt('您的年龄?', 25)
window.prompt()
的返回值有两种情况,可能是字符串(有可能是空字符串),也有可能是 null
。具体分成三种情况。
- 用户输入信息,并点击“确定”,则用户输入的信息就是返回值
- 用户没有输入信息,直接点击“确定”,则输入框的默认值就是返回值
- 用户点击了“取消”(或者按了 ESC 按钮),则返回值是
null
window.confirm()
方法弹出的对话框,除了提示信息之外,只有“确定”和“取消”两个按钮,往往用来征询用户是否同意。
var result = confirm('你最近好吗?');
confirm
方法返回一个布尔值,如果用户点击“确定”,返回 true
;如果用户点击“取消”,则返回 false
。
var okay = confirm('Please confirm this message.');
if (okay) {
// 用户按下“确定”
} else {
// 用户按下“取消”
}
这三个方法都具有堵塞效应,一旦弹出对话框,整个页面就是暂停执行,等待用户做出反应。
window.open()
、window.close()
和 window.stop()
window.open
方法用于新建另一个浏览器窗口,类似于浏览器菜单的新建窗口选项。它会返回新窗口的引用,如果无法新建窗口,则返回 null
。
open
方法一共可以接受三个参数。
window.open(url, windowName, [windowFeatures])
-url
:字符串,表示新窗口的网址。如果省略,默认网址就是 about:blank
windowName
:字符串,表示新窗口的名字。如果该名字的窗口已经存在,则占用该窗口,不再新建窗口。如果省略,就默认使用_blank
,表示新建一个没有名字的窗口。另外还有几个预设值,_self
表示当前窗口,_top
表示顶层窗口,_parent
表示上一层窗口windowFeatures
:字符串,内容为逗号分隔的键值对,表示新窗口的参数,比如有没有提示栏、工具条等等。如果省略,则默认打开一个完整 UI 的新窗口。如果新建的是一个已经存在的窗口,则该参数不起作用,浏览器沿用以前窗口的参数
var popup = window.open(
'somepage.html',
'DefinitionsWindows',
'height=200,width=200,location=no,status=yes,resizable=yes,scrollbars=yes'
);
第三个参数可以设定的属性非常多,这里不作具体介绍。
window.close()
用于关闭当前窗口,一般只用来关闭 window.open()
新建的窗口。
window.stop()
完全等同于单击浏览器的停止按钮,会停止加载图像、视频等正在或等待加载的对象。
window.scrollTo()
、window.scroll()
和 window.scrollBy()
window.scrollTo()
用于将文档滚动到指定位置。它接受两个参数,表示滚动后位于窗口左上角的页面坐标。
window.scrollTo(x-coord, y-coord)
它也可以接受一个配置对象作为参数。
window.scrollTo(options)
配置对象 options
有三个属性。
top
:滚动后页面左上角的垂直坐标,即 y 坐标left
:滚动后页面左上角的水平坐标,即 x 坐标behavior
:字符串,表示滚动的方式,有三个可能值(smooth
、instant
、auto
),默认值为auto
window.scroll()
方法是 window.scrollTo()
方法的别名。
window.scrollBy()
方法用于将网页滚动指定距离(单位像素)。它接受两个参数:水平向右滚动的像素,垂直向下滚动的像素。
如果不是要滚动整个文档,而是要滚动某个元素,可以使用下面三个属性和方法。
- Element.scrollTop
- Element.scrollLeft
- Element.scrollIntoView()
window.print()
跳出打印对话框,与用户点击菜单里面的“打印”命令效果相同。
常见的打印按钮代码如下。
document.getElementById('printLink').onclick = function () {
window.print();
}
window.focus()
和 window.blur()
window.focus()
方法会激活窗口,使其获得焦点,出现在其他窗口的前面。
var popup = window.open('popup.html', 'Popup Window');
if ((popup !== null) && !popup.closed) {
popup.focus();
}
window.blur()
方法将焦点从窗口移除。
当前窗口获得焦点时,会触发 focus
事件;当前窗口失去焦点时,会触发 blur
事件。
window.requestAnimationFrame()
window.requestAnimationFrame()
方法跟 setTimeout
类似,都是推迟某个函数的执行。不同之处在于,setTimeout
必须指定推迟的时间,window.requestAnimationFrame()
则是推迟到浏览器下一次重流时执行,执行完才会进行下一次重绘。重绘通常是 16ms 执行一次,不过浏览器会自动调节这个速率,比如网页切换到后台 Tab 页时,requestAnimationFrame()
会暂停执行。
如果某个函数会改变网页的布局,一般就放在 window.requestAnimationFrame()
里面执行,这样可以节省系统资源,使得网页效果更加平滑。因为慢速设备会用较慢的速率重流和重绘,而速度更快的设备会有更快的速率。
该方法接受一个回调函数作为参数。
window.requestAnimationFrame(callback)
callback
是一个回调函数。callback执行时,它的参数就是系统传入的一个高精度时间戳(performance.now()的返回值),单位是毫秒,表示距离网页加载的时间。
window.requestAnimationFrame()
的返回值是一个整数,这个整数可以传入window.cancelAnimationFrame()
,用来取消回调函数的执行。
下面是一个 window.requestAnimationFrame()
执行网页动画的例子。
var element = document.getElementById('animate');
element.style.position = 'absolute';
var start = null;
function step(timestamp) {
if (!start) start = timestamp;
var progress = timestamp - start;
// 元素不断向左移,最大不超过200像素
element.style.left = Math.min(progress / 10, 200) + 'px';
// 如果距离第一次执行不超过 2000 毫秒,
// 就继续执行动画
if (progress < 2000) {
window.requestAnimationFrame(step);
}
}
window.requestAnimationFrame(step);
上面代码定义了一个网页动画,持续时间是2秒,会让元素向右移动。
window.requestIdleCallback()
window.requestIdleCallback()
跟 setTimeout
类似,也是将某个函数推迟执行,但是它保证将回调函数推迟到系统资源空闲时执行。也就是说,如果某个任务不是很关键,就可以使用 window.requestIdleCallback()
将其推迟执行,以保证网页性能。
它跟 window.requestAnimationFrame()
的区别在于,后者指定回调函数在下一次浏览器重排时执行,问题在于下一次重排时,系统资源未必空闲,不一定能保证在16毫秒之内完成;window.requestIdleCallback()
可以保证回调函数在系统资源空闲时执行。
该方法接受一个回调函数和一个配置对象作为参数。配置对象可以指定一个推迟执行的最长时间,如果过了这个时间,回调函数不管系统资源有无空虚,都会执行。
window.requestIdleCallback(callback[, options])
callback
参数是一个回调函数。该回调函数执行时,系统会传入一个 IdleDeadline
对象作为参数。IdleDeadline
对象有一个 didTimeout
属性(布尔值,表示是否为超时调用)和一个 timeRemaining()
方法(返回该空闲时段剩余的毫秒数)。
options
参数是一个配置对象,目前只有 timeout
一个属性,用来指定回调函数推迟执行的最大毫秒数。该参数可选。
window.requestIdleCallback()
方法返回一个整数。该整数可以传入window.cancelIdleCallback()
取消回调函数。
requestIdleCallback(myNonEssentialWork);
function myNonEssentialWork(deadline) {
while (deadline.timeRemaining() > 0) {
doWorkIfNeeded();
}
}
上面代码中,requestIdleCallback()
用来执行非关键任务 myNonEssentialWork
。该任务先确认本次空闲时段有剩余时间,然后才真正开始执行任务。
requestIdleCallback(processPendingAnalyticsEvents, { timeout: 2000 });
上面代码指定,processPendingAnalyticsEvents
必须在未来2秒之内执行。
如果由于超时导致回调函数执行,则 deadline.timeRemaining()
返回 0
,deadline.didTimeout
返回 true
。
如果多次执行 window.requestIdleCallback()
,指定多个回调函数,那么这些回调函数将排成一个队列,按照先进先出的顺序执行。
事件
这里介绍 window
对象的四个事件:
load
事件onload
事件error
事件onerror
事件
load
事件和 onload
事件
load
事件发生在文档在浏览器窗口加载完毕时。window.onload
属性可以指定这个事件的回调函数。
window.onload = function() {
var elements = document.getElementsByClassName('example');
for (var i = 0; i < elements.length; i++) {
var elt = elements[i];
// ...
}
};
error
事件和 onerror
事件
浏览器脚本发生错误时,会触发 window
对象的 error
事件。我们可以通过window.onerror
属性对该事件指定回调函数。
window.onerror = function (message, filename, lineno, colno, error) {
console.log("出错了!--> %s", error.stack);
};
由于历史原因,window
的 error
事件的回调函数不接受错误对象作为参数,而是一共可以接受五个参数,它们的含义依次如下。
- 出错信息
- 出错脚本的网址
- 行号
- 列号
- 错误对象
老式浏览器只支持前三个参数。
多窗口操作
由于网页可以使用 iframe
元素,嵌入其他网页,因此一个网页之中会形成多个窗口。如果子窗口之中又嵌入别的网页,就会形成多级窗口。
窗口的引用
各个窗口之中的脚本,可以引用其他窗口。浏览器提供了一些特殊变量,用来返回其他窗口。
top
:顶层窗口,即最上层的那个窗口parent
:父窗口self
:当前窗口,即自身
下面代码可以判断,当前窗口是否为顶层窗口。
if (window.top === window.self) {
// 当前窗口是顶层窗口
} else {
// 当前窗口是子窗口
}
下面的代码让父窗口的访问历史后退一次。
window.parent.history.back();
与这些变量对应,浏览器还提供一些特殊的窗口名,供 window.open()
方法、<a>
标签、<form>
标签等引用。
_top
:顶层窗口_parent
:父窗口_blank
:新窗口
下面代码就表示在顶层窗口打开链接。
<a href="somepage.html" target="_top">Link</a>
对于 iframe
嵌入的窗口,document.getElementById()
可以拿到该窗口的 DOM 节点,然后使用 contentWindow
属性获得 iframe
节点包含的 window
对象。
var frame = document.getElementById('theFrame');
var frameWindow = frame.contentWindow;
上面代码中,frame.contentWindow
可以拿到子窗口的 window
对象。然后,在满足同源限制的情况下,可以读取子窗口内部的属性。
// 获取子窗口的标题
frameWindow.title
<iframe>
元素的 contentDocument
属性,可以拿到子窗口的 document
对象。
var frame = document.getElementById('theFrame');
var frameDoc = frame.contentDocument;
// 等同于
var frameDoc = frame.contentWindow.document;
<iframe>
元素遵守同源政策,只有当父窗口与子窗口在同一个域时,两者之间才可以用脚本通信,否则只有使用 window.postMessage
方法。
<iframe>
窗口内部,使用 window.parent
引用父窗口。如果当前页面没有父窗口,则window.parent
属性返回自身。因此,可以通过 window.parent
是否等于 window.self
,判断当前窗口是否为 iframe
窗口。
if (window.parent !== window.self) {
// 当前窗口是子窗口
}
<iframe>
窗口的 window
对象,有一个 frameElement
属性,返回 <iframe>
在父窗口中的 DOM 节点。对于非嵌入的窗口,该属性等于 null
。
var f1Element = document.getElementById('f1');
var f1Window = f1Element.contentWindow;
f1Window.frameElement === f1Element // true
window.frameElement === null // true
window.frames
属性
window.frames
属性返回一个类似数组的对象,成员是所有子窗口的 window
对象。可以使用这个属性,实现窗口之间的互相引用。比如,frames[0]
返回第一个子窗口,frames[1].frames[2]
返回第二个子窗口内部的第三个子窗口,parent.frames[1]
返回父窗口的第二个子窗口。
注意,window.frames
每个成员的值,是框架内的窗口(即框架的 window
对象),而不是 iframe
标签在父窗口的 DOM 节点。如果要获取每个框架内部的 DOM 树,需要使用window.frames[0].document
的写法。
另外,如果 <iframe>
元素设置了 name
或 id
属性,那么属性值会自动成为全局变量,并且可以通过 window.frames
属性引用,返回子窗口的 window
对象。
// HTML 代码为 <iframe id="myFrame">
window.myFrame // [HTMLIFrameElement]
frames.myframe === myFrame // true
另外,name
属性的值会自动成为子窗口的名称,可以用在 window.open
方法的第二个参数,或者 <a>
和 <frame>
标签的 target
属性。