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 相关文章推荐
响应鼠标变换表格背景或者颜色的代码
Mar 30 Javascript
javascript中运用闭包和自执行函数解决大量的全局变量问题
Dec 30 Javascript
js复制到剪切板的实例方法
Jun 28 Javascript
AngularJS在IE8的不支持的解决方法
May 13 Javascript
jQuery属性选择器用法示例
Sep 09 Javascript
JS+HTML5 FileReader对象用法示例
Apr 07 Javascript
Angular2 父子组件通信方式的示例
Jan 29 Javascript
Vue.js实现立体计算器
Feb 22 Javascript
JavaScript实现指定数量的并发限制的示例代码
Mar 10 Javascript
Jquery ajax书写方法代码实例解析
Jun 12 jQuery
js实现简单的点名器随机色实例代码
Sep 20 Javascript
JS中如何优雅的使用async await详解
Oct 05 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安全性漫谈
2012/06/28 PHP
用php随机生成福彩双色球号码的2种方法
2013/02/04 PHP
解析PHP中的内存管理,PHP动态分配和释放内存
2013/06/28 PHP
浅析PHP类的反射来实现依赖注入过程
2018/02/06 PHP
Laravel5.5 视图 - 创建视图和数据传递示例
2019/10/21 PHP
php 下 html5 XHR2 + FormData + File API 上传文件操作实例分析
2020/02/28 PHP
用js实现的页面关键字密度查询代码
2007/12/27 Javascript
JavaScript实现跑马灯抽奖活动实例代码解析与优化(一)
2016/02/16 Javascript
jQuery使用zTree插件实现树形菜单和异步加载
2016/02/25 Javascript
JS表单验证的代码(常用)
2016/04/08 Javascript
jQuery设置和获取select、checkbox、radio的选中值方法
2017/01/01 Javascript
jquery实现input框获取焦点的方法
2017/02/06 Javascript
基于iScroll实现下拉刷新和上滑加载效果
2017/07/18 Javascript
javascript  删除select中的所有option的实例
2017/09/17 Javascript
详解.vue文件中style标签的几个标识符
2018/07/17 Javascript
Angularjs实现页面模板清除的方法
2018/07/20 Javascript
JavaScript基于遍历操作实现对象深拷贝功能示例
2019/03/05 Javascript
详解VUE Element-UI多级菜单动态渲染的组件
2019/04/25 Javascript
探索浏览器页面关闭window.close()的使用详解
2020/08/21 Javascript
[01:32:10]NAVI vs VG Supermajor 败者组 BO3 第一场 6.5
2018/06/06 DOTA
对python中Librosa的mfcc步骤详解
2019/01/09 Python
django celery redis使用具体实践
2019/04/08 Python
在Python中获取操作系统的进程信息
2019/08/27 Python
Python实现使用dir获取类的方法列表
2019/12/24 Python
浅析pip安装第三方库及pycharm中导入第三方库的问题
2020/03/10 Python
python numpy库np.percentile用法说明
2020/06/08 Python
python属于解释型语言么
2020/06/15 Python
HTML5教程之html 5 本地数据库(Web Sql Database)
2014/04/03 HTML / CSS
RentCars.com巴西:汽车租赁网站
2016/08/22 全球购物
FILA斐乐中国官方商城:意大利运动品牌
2017/01/25 全球购物
Boden澳大利亚官网:英国在线服装公司
2018/08/05 全球购物
CNC数控操作工岗位职责
2013/11/19 职场文书
绩效工资分配方案
2014/01/18 职场文书
连带责任保证书
2014/04/29 职场文书
生产车间主任岗位职责
2015/04/08 职场文书
详解Vue3使用axios的配置教程
2022/04/29 Vue.js