在开发的时候,经常有些操作需要等 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事件的实现