这篇文章主要介绍了Javascript封装DOMContentLoaded事件实例,DOMContentLoaded是FF,Opera9的特有的Event,当所有DOM解析完以后会触发这个事件,需要的朋友可以参考下

最近在写一个Javascript的框架,刚把DOMContentLoaded事件封装好,略带小兴奋,把开发过程中遇到的原理和兼容性问题做篇笔记,省的忘记到处找。

我们在写js代码的时候,一般都会添加window.onload事件,主要是为了在DOM加载完后可以使用getElementById,getElementsByTagName等方法选取DOM元素进行操作,但是window.load会等到加载完DOM、脚本、CSS,最后加载完图片甚至是iframe中的所有资源才会触发,很多时候网页的图片较多较大,要等最后图片这个耗时大户加载完才执行js明显有些太迟了,很多时候都会影响用户体验。

很多js框架都有个document.ready的功能,像JQuery的$(document).ready()方法,可以在DOM加载完就立即执行js代码,让图片自个慢慢加载吧。

document.ready的核心是DOMContentLoaded事件,firefox、chrome、opera、safari、ie9+都可以使用addEventListener(‘DOMContentLoaded',fn,false)进行事件绑定,而ie6~8不支持DOMContentLoaded事件,所以要针对ie6~8做兼容性处理。

资料上说ie6~8可以使用document.onreadystatechange事件监听document.readyState状态是否等于complete来判断DOM是否加载完毕,如果页面中嵌有iframe的话,ie6~8的document.readyState会等到iframe中的所有资源加载完才会变成complete,此时iframe变成了耗时大户。但是经过测试,即使页面中没有iframe,当readyState等于complete时,实际触发的是onload事件而不是DOMContentLoaded事件,对这点表示惊奇。

还好ie有个特有的doScroll方法,当页面DOM未加载完成时,调用doScroll方法时,就会报错,反过来,只要一直间隔调用doScroll直到不报错,那就表示页面DOM加载完毕了,不管图片和iframe中的内容是否加载完毕,此法都有效。

如果有多个js文件绑定了document.ready事件,为了防止浏览器重复绑定,同时有序执行,可以引入一个事件队列机制来解决。

以上就是document.ready事件的原理和兼容性问题,下面贴段实例代码,为了方便理解执行过程,使用函数封装的模式,执行过程都写在注释里了,如果有不妥之处欢迎指教。


//保存domReady的事件队列
eventQueue = [];

//判断DOM是否加载完毕
isReady = false;

//判断DOMReady是否绑定
isBind = false;

/*执行domReady()
 *
 *@param  {function}
 *@execute  将事件处理程序事件队列,并绑定DOMContentLoaded
 *  如果DOM加载已经完成,则立即执行
 *@caller
 */
function domReady(fn){
if (isReady) {
fn.call(window);
}
else{
eventQueue.push(fn);
};

bindReady();
};

/*domReady事件绑定
 *
 *@param  null
 *@execute  现代浏览器通过addEvListener绑定DOMContentLoaded,包括ie9+
ie6-8通过判断doScroll判断DOM是否加载完毕
 *@caller domReady()
 */
function bindReady(){
if (isReady) return;
if (isBind) return;
isBind = true;

if (window.addEventListener) {
document.addEventListener('DOMContentLoaded',execFn,false);
}
else if (window.attachEvent) {
doScroll();
};
};

/*doScroll判断ie6-8的DOM是否加载完成
 *
 *@param  null
 *@execute  doScroll判断DOM是否加载完成
 *@caller bindReady()
 */
function doScroll(){
try{
document.documentElement.doScroll('left');
}
catch(error){
return setTimeout(doScroll,20);
};
execFn();
};

/*执行事件队列
 *
 *@param  null
 *@execute  循环执行队列中的事件处理程序
 *@caller bindReady()
 */
function execFn(){
if (!isReady) {
isReady = true;
for (var i = 0; i < eventQueue.length; i++) {
eventQueue[i].call(window);
};
eventQueue = [];
};
};

//js文件1
domReady(function(){
...
});
//js文件2
domReady(function(){
...
});

//注意,如果是异步加载的js就不要绑定domReady方法,不然函数不会执行,
//因为异步加载的js下载之前,DOMContentLoaded已经触发,addEventListener执行时已经监听不到了

测试页面:都加载了两张很大的图片,onload需要图片加载完才能执行js,DOMContentLoaded只需等到DOM加载完即可执行js。可以打开firebug查看加载过程,每次测试前记得先清理下浏览器缓存。

最新资讯
裁判也是高危职业?这些“大杀器”体育运动的误伤非同小可

裁判也是高危职业?这些

本月初,在网球大满贯美国公开赛上,名将德约科维奇因为用
精细到发丝还不够,Adobe新方法能处理6000×6000高分辨率图像

精细到发丝还不够,Adob

如何突破硬件限制,将抠图方法应用于高分辨率图像?来自 U
华为彭中阳:数字化不是零和游戏 面对挑战华为会更加开放

华为彭中阳:数字化不是

在今日的华为全联接大会上,华为董事、企业BG总裁彭中阳
趣头条谋变:战略调整 逃离亏损泥潭

趣头条谋变:战略调整

互联网的“中国速度”造就了很多明星公司,掀起一波又一
马斯克又画饼:特斯拉跑1000公里、卖17万、还不用人开……

马斯克又画饼:特斯拉跑

埃隆·马斯克在学习苹果这件事情上,越来越游刃有余了。
泡面为什么一定要泡3分钟?万万没想到,竟是利用这个特点

泡面为什么一定要泡3

泡面为什么一定要泡3分钟呢?2分钟或者4分钟不行吗?
最新文章
详解Vue的ref特性的使用

详解Vue的ref特性的使

这篇文章主要介绍了详解Vue的ref特性的使用,文中通过
vue学习笔记之slot插槽基本用法实例分析

vue学习笔记之slot插

这篇文章主要介绍了vue学习笔记之slot插槽基本用法,结
vue跳转方式(打开新页面)及传参操作示例

vue跳转方式(打开新页

这篇文章主要介绍了vue跳转方式(打开新页面)及传参操作,
vue学习笔记之过滤器的基本使用方法实例分析

vue学习笔记之过滤器

这篇文章主要介绍了vue学习笔记之过滤器的基本使用方
js获取本日、本周、本月的时间代码

js获取本日、本周、本

本篇文章给大家分享的内容是利用js如何获取本日、本周
node crawler如何添加promise支持

node crawler如何添加

这篇文章主要介绍了node crawler如何添加promise支持,