网页浏览相关 window/document 事件

网页浏览相关 window/document 事件

Chris Yue No Comment
Posts

在 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 方法:

比较奇怪的是这个事件的命名方式居然不是常见的全小写,第一眼看到这个事件的时候我还以为看错了……

visibilitychange

可能很多人都不知道这个事件,从名字上可以看得出来它是跟隐藏/显示有关系的,另外 document 上还有两个属性跟这个事件关系非常紧密,一个是 document.hidden,还有一个是 document.visibilityState。hidden 这个属性就是字面意思,布尔值,没啥好解释的,但 visibilityState 除了一看就懂的 "visible""hiden" 两个值,还有:

  1. "prerender" 页面被渲染前的状态
  2. "unloaded" 页面从内存里清除掉后的状态

目前浏览器对此属性的支持不太一样,Firefox 测试的结果是连后退前进也会触发此事件,而 Google Chrome 不会,但正常的标签页切换以及窗口最小化,两个浏览器都是可以的。

注意:此事件处理器也只能通过 document.addEventListener 来注册

window

load

此事件应该说出镜率还是比较高,前面也有提到过它。前面也解释过,load 事件在页面所有资源,包括图片,CSS,以及 frame 里的页面加载完毕的时候会触发,这里就不用多说了。

unload

与 load 对应的事件。unload 事件发生的时候,页面正处在一种资源依然存在,但界面对用户已不可见,并且所有交互功能(比如 alert 或者 confirm 等)都停止工作的时刻。所以在 unload 时,alert 等函数是不会起作用的。

除此之外,unload 还有一个特点是事件无法被阻止,也就是说 e.preventDefault,甚至是 javascript 脚本执行出现错误,都是无法阻止页面被关闭或者跳转的。

另外如果给页面的 unload 事件注册事件处理器,是会破坏 BFCache 的,即使是只赋值一个空函数:

BFCache 是什么?BFCache 的全称是 back-forward cache,也就是『前进/后退缓存』。可能你不知道它的名字,但用过浏览器的人都应该很熟悉,是的,当你在浏览器里点后退(或者前进)的时候,大部分情况,前一个页面已经被浏览器缓存住了,并且保留了前一个页面 Javascript 执行后的状态,所以后退的时候浏览器直接加载缓存里的内容,从而跳过再次从远端加载的过程。

而一旦 BFCache 被破坏,后退或者前进的时候,会再次从远端加载内容并且重新执行 Javascript。在做某些跟历史浏览相关的编码时一定要特别小心这点。

beforeunload

看名字都能看出来,这个事件发生在 unload 事件之前,具体说来,是在 document 对象及其所有资源要被回收的时候调用的。所以不同于 unload 事件,beforeunload 发生时,浏览器还可以与用户交互。其实在实际应用中,此事件经常用来在用户离开页面前,询问用户是否确认要离开:

但除此方法可以同用户交互外,alertconfirmprompt 这几个方法在此方法里都会被忽略,这是 HTML5 specification 里规定的行为。

需要注意的是,监听此事件也会破坏掉 BFCache。

pageshow

此事件发生在页面被显示的时候。不同于 document.visibilitychange,此事件在

  1. 前进/后退进入页面并显示页面内容的时候会触发
  2. 或者新页面在 onload 事件发生后也会触发

此事件的事件对象比普通事件对象多了一个参数叫做 persisted,用来表示当前重见天日的页面是刚下载的,还是从历史缓存里取的:

但需要注意的是,目前浏览器对于此事件的支持度还不够,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.

微信赞赏码

文章可赞,扫码赏饭!
天使投赏人

发表评论

20 − = 11