Javascript封装DOMContentLoaded事件实例


Posted in Javascript onJune 12, 2014

最近在写一个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查看加载过程,每次测试前记得先清理下浏览器缓存。

Javascript 相关文章推荐
JavaScript省市联动实现代码
Feb 15 Javascript
JQuery教学之性能优化
May 14 Javascript
微信JSSDK上传图片
Aug 23 Javascript
Javascript实现单例模式
Jan 24 Javascript
JS实现点击登录弹出窗口同时背景色渐变动画效果
Mar 25 Javascript
基于JQuery的$.ajax方法进行异步请求导致页面闪烁的解决办法
May 10 Javascript
js 基础篇必看(点击事件轮播图的简单实现)
Aug 20 Javascript
Angular4.0中引入laydate.js日期插件的方法教程
Dec 25 Javascript
webpack源码之loader机制详解
Apr 06 Javascript
详解js中Array的方法及技巧
Sep 12 Javascript
JS添加或删除HTML dom元素的方法实例分析
Mar 05 Javascript
微信小程序实现点击生成随机验证码
Sep 09 Javascript
自己封装的javascript事件队列函数版
Jun 12 #Javascript
jquery动态添加删除一行数据示例
Jun 12 #Javascript
checkbox勾选判断代码分析
Jun 11 #Javascript
百度判断手机终端并自动跳转js代码及使用实例
Jun 11 #Javascript
js获取日期:昨天今天和明天、后天
Jun 11 #Javascript
js使用栈来实现10进制转8进制与取除数及余数
Jun 11 #Javascript
删除javascript中注释语句的正则表达式
Jun 11 #Javascript
You might like
phpcms手机内容页面添加上一篇和下一篇
2015/06/05 PHP
PHP简单实现模拟登陆功能示例
2017/09/15 PHP
PHP中十六进制颜色与RGB颜色值互转的方法
2019/03/18 PHP
PHP单文件上传原理及上传函数的封装操作示例
2019/09/02 PHP
php实现登录页面的简单实例
2019/09/29 PHP
javascript hashtable实现代码
2009/10/13 Javascript
jquery 关键字“拖曳搜索”之“拖曳”以及 图片“提示自适应放大”效果 的实现
2010/04/18 Javascript
动态创建样式表在各浏览器中的差异测试代码
2011/09/13 Javascript
页面加载完毕后滚动条自动滚动一定位置
2014/02/20 Javascript
js 获取页面高度和宽度兼容 ie firefox chrome等
2014/05/14 Javascript
基于jQuery Bar Indicator 插件实现进度条展示效果
2015/09/30 Javascript
jquery+json实现动态商品内容展示的方法
2016/01/14 Javascript
AngularJS教程之简单应用程序示例
2016/08/16 Javascript
jQuery时间验证和转换为标准格式的时间格式
2017/03/06 Javascript
通过vue-router懒加载解决首次加载时资源过多导致的速度缓慢问题
2018/04/08 Javascript
[01:23]一分钟告诉你 DOTA2为什么叫信仰2
2014/06/20 DOTA
[45:16]完美世界DOTA2联赛PWL S3 Magma vs Phoenix 第一场 12.12
2020/12/16 DOTA
Python中dictionary items()系列函数的用法实例
2014/08/21 Python
python 性能优化方法小结
2017/03/31 Python
利用python将图片转换成excel文档格式
2017/12/30 Python
对Python 获取类的成员变量及临时变量的方法详解
2019/01/22 Python
Python学习笔记基本数据结构之序列类型list tuple range用法分析
2019/06/08 Python
Python:Numpy 求平均向量的实例
2019/06/29 Python
python实现两张图片拼接为一张图片并保存
2019/07/16 Python
python数据库操作mysql:pymysql、sqlalchemy常见用法详解
2020/03/30 Python
奥地利网上现代灯具和灯饰店:Lampenwelt.at
2018/01/29 全球购物
新加坡网上化妆品店:Best Buy World
2018/05/18 全球购物
农村婚礼证婚词
2014/01/08 职场文书
乡镇个人对照检查材料
2014/08/22 职场文书
大学生见习期满自我鉴定
2014/09/13 职场文书
2014年光棍节活动策划方案(创意集锦)
2014/09/29 职场文书
2014年安全生产工作总结
2014/11/13 职场文书
幼儿园中班教师个人工作总结
2015/02/06 职场文书
金砖之国观后感
2015/06/11 职场文书
2016关于军训的心得体会
2016/01/11 职场文书
Shell中的单中括号和双中括号的用法详解
2022/12/24 Servers