在开发的时候,经常有些操作需要等 DOM 完成后才执行,比如为某个按钮绑定事件、为防止抖动,在页面内容加载完成后才展示页面。这里我们看一下和页面加载有关的一些事件。
window.onload
在文档装载完成后会触发 onload
事件。此时,在文档中的所有对象都在 DOM 中,所有图片,脚本,链接以及子框都完成了装载。
如果在 onload
的事件函数里面,再次监听 onload
事件,那么,是不会再次触发函数的。
function addOnload(callback) { |
如上,因此,对于异步加载的JS,为了保证能在 onload
里面触发,可以先判断 document.readystate === "complete"
,如果成功,则立即执行函数:
function addOnload(callback) { |
onload
需要等所有的资源加载完成才执行,当资源过多过大时,onload
会出现比较严重的延迟问题,严重影响用户体验。
DOMContentLoaded
当初始 HTML 文档被完全加载和解析时,DOMContentLoaded
事件被触发,而无需等待样式表、图像和子框架完成加载。
window.onload = function () { |
如果 script
标签中包含 defer
,那么 HTML 文档构建不受影响,而 DOMContentLoaded
只有在 defer
脚本执行结束后才会被触发。
如果 script
标签中包含 async
,则 HTML 文档构建不受影响,解析完毕后,DOMContentLoaded
触发,而不需要等待 async
脚本执行、样式表加载等等。
JQuery
等框架中的 ready
方法实际上主要就是采用 DOMContentLoaded
实现的,而 load
方法监听的是 onload
事件。
该方法在 IE 9-
以下不被支持,但是可以采用下面几节介绍的内容实现。
onreadystatechange 事件
该事件提供与文档的加载状态有关的信息。支持 onreadystatechange
事件的每个对象都有一个 readyState
属性,它的属性包含以下五个值:
uninitialized
尚未初始化,对象已经存在但尚未初始化。loading
正在加载中,对象正在加载数据。loaded
加载完毕,对象加载数据完成。interactive
可交互,可以操作 DOM 对象了,但还没有完全加载。complete
完成,对象已经加载完毕。
当这个属性的值变化时,document
对象上的 readystatechange
事件将被触发。如下,回调函数被执行2次:·
document.onreadystatechange = function () { |
如果在文档的不同状态绑定事件,可以用来模拟 onload
和 近似模拟 DOMContentLoaded
事件。
模拟 onload
事件:
document.onreadystatechange = function () { |
不严格情况下能模拟 DOMContentLoaded
:
document.onreadystatechange = function () { |
实际上 DOMContentLoaded
的执行时机是要比设置 document.readyState = "interactive"
晚的,大概顺序为 interactive
状态 -> 运行defer
脚本和其他阻塞脚本 -> DOMContentLoaded
> 运行 async
脚本 -> complete
。具体参考document.readystate of “interactive” vs. ondomcontentloaded?
因此最后一节的模拟 DOMContentLoaded
的实现并未采用这个事件来完成。
doScroll
IE 还有个特有的方法 doScroll
,当页面未加载完成时,该方法会报错。
document.documentElement.doScroll("left"); |
通过间隔调用,直到 doScroll
不再报错时,就代表 DOM 加载完成了,可以用来检测 DOM 是否加载完成。
自定义 DOMContentLoaded 事件
根据上面内容可以提供一个兼容性较好的 DOMContentLoaded
实现:
function domReady(fn){ |
更具体可以参考各个主流框架的实现 主流JS框架中DOMReady事件的实现