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 相关文章推荐
一个简单的全屏图片上下打开显示网页效果示例
Jul 08 Javascript
实例讲解JavaScript的Backbone.js框架中的View视图
May 05 Javascript
浅谈JavaScript函数的四种存在形态
Jun 08 Javascript
el表达式 写入bootstrap表格数据页面的实例代码
Jan 11 Javascript
深究AngularJS如何获取input的焦点(自定义指令)
Jun 12 Javascript
最新Javascript程序员面试试题和解题方法
Nov 23 Javascript
使用pm2部署node生产环境的方法步骤
Mar 09 Javascript
JavaScript表格隔行变色和Tab标签页特效示例【附jQuery版】
Jul 11 jQuery
layui内置模块layim发送图片添加加载动画的方法
Sep 23 Javascript
JS实现简易留言板(节点操作)
Mar 16 Javascript
解决vue项目router切换太慢问题
Jul 19 Javascript
Vue中使用import进行路由懒加载的原理分析
Apr 01 Vue.js
自己封装的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获取网卡地址的代码
2008/04/09 PHP
利用Ffmpeg获得flv视频缩略图和视频时间的代码
2011/09/15 PHP
set_include_path和get_include_path使用及注意事项
2013/02/02 PHP
js限制checkbox勾选的个数以及php获取多个checkbbox的方法深入解析
2013/07/18 PHP
php实现事件监听与触发的方法
2014/11/21 PHP
Laravel学习教程之View模块详解
2017/09/18 PHP
PHP中通过getopt解析GNU C风格命令行选项
2019/11/18 PHP
Thinkphp 框架基础之源码获取、环境要求与目录结构分析
2020/04/27 PHP
js同时按下两个方向键
2007/12/01 Javascript
所见即所得的富文本编辑器bootstrap-wysiwyg使用方法详解
2016/05/27 Javascript
关于Vue.js一些问题和思考学习笔记(1)
2016/12/02 Javascript
jQuery实现字符串全部替换的方法
2016/12/12 Javascript
在vue中使用Echarts利用watch做动态数据渲染操作
2020/07/20 Javascript
Vue项目打包部署到apache服务器的方法步骤
2021/02/01 Vue.js
python算法学习之计数排序实例
2013/12/18 Python
python列表操作使用示例分享
2014/02/21 Python
python连接字符串的方法小结
2015/07/13 Python
利用pyinstaller或virtualenv将python程序打包详解
2017/03/22 Python
LRUCache的实现原理及利用python实现的方法
2017/11/21 Python
Python快速排序算法实例分析
2017/11/29 Python
pandas Dataframe行列读取的实例
2018/06/08 Python
python实战教程之自动扫雷
2018/07/13 Python
pycharm的console输入实现换行的方法
2019/01/16 Python
Python通过TensorFlow卷积神经网络实现猫狗识别
2019/03/14 Python
django 中QuerySet特性功能详解
2019/07/25 Python
python Django框架实现web端分页呈现数据
2019/10/31 Python
如何修复使用 Python ORM 工具 SQLAlchemy 时的常见陷阱
2019/11/19 Python
python 5个顶级异步框架推荐
2020/09/09 Python
用CSS3实现瀑布流布局的示例代码
2017/11/10 HTML / CSS
测控技术与仪器个人求职信范文
2013/12/30 职场文书
毕业生求职自荐信怎么写
2014/01/08 职场文书
物资采购方案
2014/06/12 职场文书
交通事故委托书范本(2篇)
2014/09/21 职场文书
写给父母的感谢信
2015/01/22 职场文书
通知函的格式
2015/04/27 职场文书
辛亥革命观后感
2015/06/02 职场文书