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 相关文章推荐
Jquery的Tabs内容轮换效果实现代码,几行搞定
Feb 12 Javascript
js判断手机号运营商的方法
Oct 23 Javascript
JavaScript中setTimeout和setInterval函数的传参及调用
Mar 11 Javascript
Javascript 6里的4个新语法
Aug 25 Javascript
Bootstrap 3的box-sizing样式导致UEditor控件的图片无法正常缩放的解决方案
Sep 15 Javascript
在localStorage中存储对象数组并读取的方法
Sep 24 Javascript
浅谈js中同名函数和同名变量的执行问题
Feb 12 Javascript
详解A标签中href=&quot;&quot;的几种用法
Aug 20 Javascript
如何以Angular的姿势打开Font-Awesome详解
Apr 22 Javascript
Vue使用高德地图搭建实时公交应用功能(地图 + 附近站点+线路详情 + 输入提示+换乘详情)
May 16 Javascript
解决vuex刷新状态初始化的方法实现
Aug 15 Javascript
layui使用templet格式化表格数据的方法
Sep 16 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
php环境配置 php5 mysql5 apache2 phpmyadmin安装与配置
2006/11/17 PHP
PHP语法自动检查的Vim插件
2014/08/11 PHP
Yii CGridView用法实例详解
2016/07/12 PHP
PHP手机短信验证码实现流程详解
2018/05/17 PHP
gearman管理工具GearmanManager的安装与php使用方法示例
2020/02/27 PHP
小议Javascript中的this指针
2010/03/18 Javascript
Colortip基于jquery的信息提示框插件在IE6下面的显示问题修正方法
2010/12/06 Javascript
IE与FireFox中的childNodes区别
2011/10/20 Javascript
密码强度检测效果实现原理与代码
2013/01/04 Javascript
jQuery ui 利用 datepicker插件实现开始日期(minDate)和结束日期(maxDate)
2014/05/22 Javascript
Spring MVC中Ajax实现二级联动的简单实例
2016/07/06 Javascript
bootstrap提示标签、提示框实现代码
2016/12/28 Javascript
详解基于Koa2开发微信二维码扫码支付相关流程
2018/05/16 Javascript
jQuery使用动画队列自定义动画操作示例
2018/06/16 jQuery
解决layui中的form表单与button的点击事件冲突问题
2018/08/15 Javascript
vue.js路由mode配置之去掉url上默认的#方法
2019/11/01 Javascript
vue实现数据控制视图的原理解析
2020/01/07 Javascript
webpack的 rquire.context用法实现工程自动化的方法
2020/02/07 Javascript
python字符串排序方法
2014/08/29 Python
深入讲解Python中的迭代器和生成器
2015/10/26 Python
python3基于TCP实现CS架构文件传输
2018/07/28 Python
python re库的正则表达式入门学习教程
2019/03/08 Python
Python Django实现layui风格+django分页功能的例子
2019/08/29 Python
Python树莓派学习笔记之UDP传输视频帧操作详解
2019/11/15 Python
python 实现批量替换文本中的某部分内容
2019/12/13 Python
python十进制转二进制的详解
2020/02/07 Python
html5教程画矩形代码分享
2013/12/04 HTML / CSS
Tuckernuck官网:经典的美国品质服装、鞋子和配饰
2021/01/11 全球购物
房地产广告词大全
2014/03/19 职场文书
党校培训自我鉴定范文
2014/03/20 职场文书
诚信考试承诺书
2014/03/27 职场文书
计算机售后服务承诺书
2014/05/30 职场文书
体育馆的标语
2014/06/24 职场文书
音乐课外活动总结
2015/05/09 职场文书
幼儿园音乐教学反思
2016/02/18 职场文书
Python list去重且保持原顺序不变的方法
2021/04/03 Python