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学习笔记(十二) RegExp类型介绍
Jun 20 Javascript
window.requestAnimationFrame是什么意思,怎么用
Jan 13 Javascript
解析js原生方法创建表格效率测试
Jul 08 Javascript
JS+flash实现chrome和ie浏览器下同时可以复制粘贴
Sep 22 Javascript
jQuery学习笔记之jQuery构建函数的7种方法
Jun 03 Javascript
JS实现一个列表中包含上移下移删除等功能
Sep 24 Javascript
使用angular写一个hello world
Jan 23 Javascript
JavaScript function函数种类详解
Feb 22 Javascript
javascript的几种写法总结
Sep 30 Javascript
js实现按钮开关单机下拉菜单效果
Nov 22 Javascript
微信小程序制作表格的方法
Feb 14 Javascript
原生Js 实现的简单无缝滚动轮播图的示例代码
May 10 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
深入了解php4(1)--回到未来
2006/10/09 PHP
PHP 文件类型判断代码
2009/03/13 PHP
php selectradio和checkbox默认选择的实现方法详解
2013/06/29 PHP
Yii使用CLinkPager分页实例详解
2014/07/23 PHP
php函数实现判断是否移动端访问
2015/03/03 PHP
支持中文的PHP按字符串长度分割成数组代码
2015/05/17 PHP
Yii2.0中使用js异步删除示例
2017/03/10 PHP
各浏览器对click方法的支持差异小结
2011/07/31 Javascript
Javascript遍历table中的元素示例代码
2014/07/08 Javascript
jQuery中:hidden选择器用法实例
2014/12/30 Javascript
使用jQuery.Qrcode插件在客户端动态生成二维码并添加自定义Logo
2016/09/01 Javascript
详解vue 中使用 AJAX获取数据的方法
2017/01/18 Javascript
浅析node.js的模块加载机制
2018/05/25 Javascript
解决JavaScript中0.1+0.2不等于0.3问题
2018/10/23 Javascript
Vue $mount实战之实现消息弹窗组件
2019/04/22 Javascript
JQuery事件委托(适用于给动态生成的脚本元素添加事件)
2020/02/01 jQuery
javascript实现时间日期的格式化的方法汇总
2020/08/06 Javascript
VsCode里的Vue模板的实现
2020/08/12 Javascript
Django中实现点击图片链接强制直接下载的方法
2015/05/14 Python
python的文件操作方法汇总
2017/11/10 Python
python代理工具mitmproxy使用指南
2019/07/04 Python
Python爬取破解无线网络wifi密码过程解析
2019/09/17 Python
python中的函数递归和迭代原理解析
2019/11/14 Python
Django form表单与请求的生命周期步骤详解
2020/06/07 Python
python学习将数据写入文件并保存方法
2020/06/07 Python
css3实现可拖动的魔方3d效果
2019/05/07 HTML / CSS
英国名牌男装店:Standout
2021/02/17 全球购物
泰国排名第一的家居用品中心:HomePro
2020/11/18 全球购物
安全责任书范文
2014/03/12 职场文书
2014年幼儿园老师工作总结
2014/12/05 职场文书
居安思危观后感
2015/06/11 职场文书
《珍珠鸟》教学反思
2016/02/16 职场文书
Golang二维切片初始化的实现
2021/04/08 Golang
深入理解Vue的数据响应式
2021/05/15 Vue.js
AJAX实现省市县三级联动效果
2021/10/16 Javascript
mysql创建存储过程及函数详解
2021/12/04 MySQL