在 DOM 的世界里有很多很多的事件,有些因为极易被感知,大家都比较熟悉,比如说 click 事件,而有些因为事件作用对象相对抽象,或者触发的时机并不是那么好描述,关注的人就比较少了,比如 window 和 document 两个对象里大量的页面浏览相关事件。
目前为未完成版本,请访问 http://www.chrisyue.com/?p=2613 查看原文是否更新。
document
readystatechange
看起来跟 Ajax 的 readystatechange
事件名一模一样,不仅如此 document 上的确也有类似 XMLHttpRequest 的 readyState
的属性 document.readyState
,并且同样的,当这个属性发生变化的时候,就会触发一次 readystatechange
事件。不过与 Ajax 不同的是,document.readyState
并不表示网络连接状态,它有完全不同于 Ajax 的 readyState 的三个值:
"loading"
表示 DOM 还在加载中。实际上我自己测试的时候,浏览器从来没触发过这个状态,我猜想是在 loading 状态时 javascript 还没有开始执行,事件处理器还没有被注册。
"interactive"
表示 DOM 已经加载完毕,但还没有加载完 css 文件,图片文件,以及 iframe 里的页面。jQuery 里推荐执行代码的时机是放在 $(document).ready()
里,其实就是 document.readyState === 'interactive'
这个时候。
说到 interactive
这个状态,不得不提到 document 的 DOMContentLoaded
事件,这个事件之后会提到。
"complete"
表示 DOM 已经完全加载完毕,包括加载完所有的 css,图片,以及 iframe 里的内容。说道 complete 状态,又必须得提到 window 的 load 事件,其实 load 事件就发生在 document.readyState
变成 complete
的那个时候。之所以 jQuery 不推荐在 window 的 load 事件执行代码,而推荐 ready
方法,就是因为 load 事件可能要等若干外部文件加载完,触发得相对较晚。其实大部分情况,javascript 代码在 interactive 状态执行就已经完全没问题了。
DOMContentLoaded
如上所说,此事件完全等同于 document.readyState === "interactive"
时触发的 onreadystatechange 事件。需要注意的是,此事件在 document 下并没有对应的 onXxxx 属性,不能通过类似 document.ondomcontentloaded = function() {}
的方式注册事件监听,而必须使用 addEventListener
方法:
document.addEventListener("DOMContentLoaded", function(e) {
console.log("dom loaded");
});
比较奇怪的是这个事件的命名方式居然不是常见的全小写,第一眼看到这个事件的时候我还以为看错了……
visibilitychange
可能很多人都不知道这个事件,从名字上可以看得出来它是跟隐藏/显示有关系的,另外 document 上还有两个属性跟这个事件关系非常紧密,一个是 document.hidden
,还有一个是 document.visibilityState
。hidden 这个属性就是字面意思,布尔值,没啥好解释的,但 visibilityState 除了一看就懂的 "visible"
和 "hiden"
两个值,还有:
"prerender"
页面被渲染前的状态"unloaded"
页面从内存里清除掉后的状态
目前浏览器对此属性的支持不太一样,Firefox 测试的结果是连后退前进也会触发此事件,而 Google Chrome 不会,但正常的标签页切换以及窗口最小化,两个浏览器都是可以的。
注意:此事件处理器也只能通过 document.addEventListener
来注册
window
load
此事件应该说出镜率还是比较高,前面也有提到过它。前面也解释过,load 事件在页面所有资源,包括图片,CSS,以及 frame 里的页面加载完毕的时候会触发,这里就不用多说了。
unload
与 load 对应的事件。unload 事件发生的时候,页面正处在一种资源依然存在,但界面对用户已不可见,并且所有交互功能(比如 alert 或者 confirm 等)都停止工作的时刻。所以在 unload 时,alert
等函数是不会起作用的。
除此之外,unload 还有一个特点是事件无法被阻止,也就是说 e.preventDefault
,甚至是 javascript 脚本执行出现错误,都是无法阻止页面被关闭或者跳转的。
另外如果给页面的 unload 事件注册事件处理器,是会破坏 BFCache 的,即使是只赋值一个空函数:
window.onunload = function() {};
BFCache 是什么?BFCache 的全称是 back-forward cache,也就是『前进/后退缓存』。可能你不知道它的名字,但用过浏览器的人都应该很熟悉,是的,当你在浏览器里点后退(或者前进)的时候,大部分情况,前一个页面已经被浏览器缓存住了,并且保留了前一个页面 Javascript 执行后的状态,所以后退的时候浏览器直接加载缓存里的内容,从而跳过再次从远端加载的过程。
而一旦 BFCache 被破坏,后退或者前进的时候,会再次从远端加载内容并且重新执行 Javascript。在做某些跟历史浏览相关的编码时一定要特别小心这点。
beforeunload
看名字都能看出来,这个事件发生在 unload 事件之前,具体说来,是在 document 对象及其所有资源要被回收的时候调用的。所以不同于 unload 事件,beforeunload 发生时,浏览器还可以与用户交互。其实在实际应用中,此事件经常用来在用户离开页面前,询问用户是否确认要离开:
window.addEventListener("beforeunload", function (e) {
var confirmationMessage = "是否离开";
e.returnValue = confirmationMessage; // Gecko, Trident, Chrome 34+
return confirmationMessage; // Gecko, WebKit, Chrome <34
});
但除此方法可以同用户交互外,alert
、confirm
、prompt
这几个方法在此方法里都会被忽略,这是 HTML5 specification 里规定的行为。
需要注意的是,监听此事件也会破坏掉 BFCache。
pageshow
此事件发生在页面被显示的时候。不同于 document.visibilitychange
,此事件在
- 前进/后退进入页面并显示页面内容的时候会触发
- 或者新页面在 onload 事件发生后也会触发
此事件的事件对象比普通事件对象多了一个参数叫做 persisted
,用来表示当前重见天日的页面是刚下载的,还是从历史缓存里取的:
window.addEventListener('pageshow', function(e) {
if (e.persisted) {
alert('显示的页面是缓存里的!');
}
});
但需要注意的是,目前浏览器对于此事件的支持度还不够,Firefox 和 Safari 没有问题,但 google chrome 直到现在,除了加载页面后会正常触发,前进/后退操作都是不会触发此事件的。根据我自己的测试,我发现只要监听了 pageshow 事件,google chrome 就不会缓存页面,后退也都会重新执行 Javascript
另外在移动端方面,Safari 和 webkit 内核的浏览器均不支持此事件。
pagehide
此事件类似于 pageshow,只不过发生在页面跳走,或者关闭之前的瞬间。抛开兼容性问题,理论上说,监听 pagehide 事件是不会导致 BFCache 失效的,所以如果需要在页面消失之前做一些事情,监听 pagehide 事件要比监听 unload 或者 beforeunload 事件要好。
网页浏览相关 window/document 事件 by Chris Yue is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

写作累,服务器还越来越贵
求分担,祝愿好人一生平安
天使打赏人