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函数内部this指针指向的三种方法
Apr 23 Javascript
用JS将搜索的关键字高亮显示实现代码
Nov 08 Javascript
javascript控制Div层透明属性由浅变深由深变浅逐渐显示
Nov 12 Javascript
JavaScript中的普通函数与构造函数比较
Apr 07 Javascript
Bootstrap入门书籍之(三)栅格系统
Feb 17 Javascript
JavaScript的Backbone.js框架入门学习指引
May 07 Javascript
JavaScript中Array的实用操作技巧分享
Sep 11 Javascript
JS实现课堂随机点名和顺序点名
Mar 09 Javascript
微信小程序实现获取自己所处位置的经纬度坐标功能示例
Nov 30 Javascript
vue.js 实现点击按钮动态添加li的方法
Sep 07 Javascript
javascript浅层克隆、深度克隆对比及实例解析
Feb 09 Javascript
vue 获取元素额外生成的data-v-xxx操作
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
印尼林东PWN黄金曼特宁咖啡豆:怎么冲世界上最醇厚的咖啡冲煮教程
2021/03/03 冲泡冲煮
真正的ZIP文件操作类(php)
2007/07/21 PHP
phpmyadmin下载、安装、配置教程
2017/05/16 PHP
解决php扩展安装不生效问题
2019/10/25 PHP
javascript 二维数组的实现与应用
2010/03/16 Javascript
jquery创建并行对象或者合并对象的实现代码
2012/10/10 Javascript
jquery连缀语法如何实现
2012/11/29 Javascript
ajax上传时参数提交不更新等相关问题
2012/12/11 Javascript
推荐 21 款优秀的高性能 Node.js 开发框架
2014/08/18 Javascript
JavaScript函数模式详解
2014/11/07 Javascript
jQuery层级选择器用法分析
2015/02/10 Javascript
jQuery模仿阿里云购买服务器选择购买时间长度的代码
2016/04/29 Javascript
微信小程序 MD5的方法详解及实例代码
2017/03/10 Javascript
vue的基本用法与常见指令
2017/08/15 Javascript
angular多语言配置详解
2019/05/16 Javascript
layui文件上传控件带更改后数据传值的方法
2019/09/23 Javascript
在vue和element-ui的table中实现分页复选功能
2019/12/04 Javascript
js实现树形数据转成扁平数据的方法示例
2020/02/27 Javascript
在vue中使用jsonp进行跨域请求接口操作
2020/10/29 Javascript
vue点击Dashboard不同内容 跳转到同一表格的实例
2020/11/13 Javascript
Python实现一个简单的MySQL类
2015/01/07 Python
完美解决安装完tensorflow后pip无法使用的问题
2018/06/11 Python
python skimage 连通性区域检测方法
2018/06/21 Python
Python常用模块之requests模块用法分析
2019/05/15 Python
python str字符串转uuid实例
2020/03/03 Python
网站域名和主机:Domain.com
2019/04/01 全球购物
俄语专业毕业生推荐信
2013/10/28 职场文书
经济管理专业毕业生推荐信
2013/11/11 职场文书
《绿色蝈蝈》教学反思
2014/03/02 职场文书
签约仪式策划方案
2014/06/02 职场文书
幼儿园八一建军节活动方案
2014/08/27 职场文书
基层党员干部四风问题整改方向和措施
2014/09/25 职场文书
就业证明函
2015/06/17 职场文书
法制教育主题班会
2015/08/13 职场文书
幽默口才训练经典句子(48句)
2019/08/19 职场文书
Android中View.post和Handler.post的关系
2022/06/05 Java/Android