原文地址: 跨浏览器的DOMContentLoaded事件
DOMContentLoaded事件是在DOM已经准备好,而其他资源可能还未下载完毕时触发的。我们可以藉此尽快的给各种交互用的dom绑定交互事件。无奈IE678不支持此事件,需要模拟。能Google到许多相关资源,比如主流框架中DOMContentLoaded事件的实现。
目前,在IE中模拟DOMContentLoaded事件有3种方法。
document.attachEvent("onreadystatechange", function(){ if ( document.readyState === "complete" ) { document.detachEvent( "onreadystatechange", arguments.callee ); //这里触发DOMContentLoaded事件 } });
//IE中 script元素的defer属性指示浏览器在dom ready之后再加载该script document.write("<"+"script id=__onDOMContentLoaded defer src=//:><\/script>"); document.getElementById("__onDOMContentLoaded").onreadystatechange = function() { if (this.readyState == "complete") { this.onreadystatechange = null; //这里触发DOMContentLoaded事件 } };
(function(){ try{ //doScroll方法只有在dom ready之后可以调用,否则会抛异常 document.documentElement.doScroll('left'); }catch(e){ window.setTimeout( arguments.callee, 0 ); return; } //这里触发DOMContentLoaded事件 })();
在3种模拟DOMContentLoaded的方法中,检测document.readyState状态的方法和检测defer的script的方法会因为页面中包含iframe而无法及时触发(要等到iframe加载完毕readyState的值才会变为complete),而调用doScroll的方法可以避免此问题。但是调用doScroll方法在脚本本身运行于iframe中时会在iframe的dom准备好之前就可以使用,我想可能是因为iframe的包含文档已经处于dom ready状态,所以导致doScroll方法可用了。
看了下jQuery-1.4.3和1.6.2的代码,选择了检测document的readyState和调用doScroll方法的组合来模拟DOMContentLoaded事件,基于上述的原因,该模拟可在页面包含iframe情况下检测doScroll方法的调用来模拟DOMContentLoaded,在包含于iframe中时检测document的readyState来模拟DOMContentLoaded。通常很少有在iframe中还有iframe的情况出现吧。jQuery源码中跨浏览器的DOMContentLoaded事件的代码可以简化为以下代码:
(function( window ){ var readyBound = false, readyList = []; var LIZ = { isReady : false, /** * 注册DOM ready时的处理函数 */ onReady: function ( fn ){ LIZ.bindReady(); // 如果此时DOM已经准备好 就直接调用注册的fn if ( LIZ.isReady ) { fn.call( document ); // 否则就把fn推入readyList } else if ( readyList ) { readyList.push( fn ); } }, /** * 触发DOM ready的函数 */ ready: function (){ var fn, i = 0, ready; //如果DOMContentLoaded还没有触发过 if( !LIZ.isReady ){ LIZ.isReady = true; if( readyList ){ //为了减少变量查询带来的性能损耗,将readyList赋值给本地变量 ready = readyList; //释放readyList引用 readyList = null; while( (fn = ready[ i++ ]) ){ fn.call( document ); } } } }, /** * 绑定DOM ready事件监听的函数 */ bindReady: function (){ if ( readyBound ) { return; } readyBound = true; //如果在绑定ready的时候DOM已经准备好了,就异步调用ready函数 if ( document.readyState === "complete" ) { return setTimeout( LIZ.ready, 0 ); } if( document.addEventListener ){ document.addEventListener( "DOMContentLoaded", function(){ document.removeEventListener( "DOMContentLoaded", arguments.callee, false ); LIZ.ready(); }, false ); window.addEventListener( "load", LIZ.ready, false ); } else if( document.attachEvent ){ //如果是IE,先监听document的onreadystatechange事件 //当document.readyState为complete时调用ready函数 //但是当文档中还包含iframe时,readyState要等到iframe加载完毕才会改变状态为complete //所以用下面的doScroll方法来检测DOM是否加载完毕 document.attachEvent("onreadystatechange", function(){ if ( document.readyState === "complete" ) { document.detachEvent( "onreadystatechange", arguments.callee ); LIZ.ready(); } }); window.attachEvent( "onload", LIZ.ready ); var isToplevel = false; try { //判断文档是否处于最顶层 isToplevel = window.frameElement == null; } catch(e) {} //如果文档处于iframe中,调用doScroll方法成功时并不代表DOM加载完毕 //所以用isToplevel标识是否使用doScroll来触发ready函数 if ( document.documentElement.doScroll && isToplevel ) { (function(){ try{ document.documentElement.doScroll('left'); }catch(e){ window.setTimeout( arguments.callee, 0 ); return; } LIZ.ready(); })(); } } } }; window.LIZ = LIZ; })(window);
jQuery源码中对DOMContentLoaded事件的模拟还考虑了js异步加载的解决方案,比如异步加载jQuery的一些插件时,也要保证其代码中绑定的ready事件可以执行。为此jQuery使用一个readyWait属性来记录异步加载代码的数量,可以通过对该属性的操作来延迟DOM ready事件的触发。jQuery1.4版本中就有该属性及相关代码的存在,但是直到jQuery1.6才出现操作该属性的公开的jQuery.holdReady方法。
关于异步加载还要研究研究,还有模块化开发,最近正在看seajs的源码,看完了再写篇读后感-。-
相关推荐
主要介绍了JS兼容所有浏览器的DOMContentLoaded事件的相关资料,标准浏览器中,使用DOMContentLoaded事件即可实现我们的要求,注册事件处理函数也极为简单,感兴趣的朋友一起学习吧
带有多个构建版本(QSA、 、 、 ) 几种元素方法用于添加更多元素方法的 API活动跨浏览器 DOMContentLoaded (domready) 跨浏览器 DOM 事件事件委托(有或没有选择器引擎)发布/订阅用于应用程序通信的发布者对象...
主要介绍了Javascript封装DOMContentLoaded事件实例,DOMContentLoaded是FF,Opera 9的特有的Event, 当所有DOM解析完以后会触发这个事件,需要的朋友可以参考下
最近在做性能有关的数据上报,发现了两个非常有意思的东西:Chrome开发者工具的Timeline分析面板,以及DOMContentLoaded事件。一个是强大的令人发指的性能分析工具,一个是重要的性能指标,于是就用Timeline对...
在文档加载时加载JavaScript 学习目标 了解DOMContentLoaded为什么如此重要 在DOMContentLoaded上设置一个... DOMContentLoaded事件是浏览器的内置方法,用于指示何时将页面的html加载到DOM中。 无法操纵尚未呈现HTM
在文档加载时加载JavaScript 学习目标 了解DOMContentLoaded为什么如此重要 在DOMContentLoaded上设置一个... DOMContentLoaded事件是浏览器的内置方法,用于指示何时将页面的html加载到DOM中。 无法操纵尚未呈现HTM
在文档加载时加载JavaScript 学习目标 了解DOMContentLoaded为什么如此重要 在DOMContentLoaded上设置一个... DOMContentLoaded事件是浏览器的内置方法,用于指示何时将页面的html加载到DOM中。 无法操纵尚未呈现HTM
在文档加载时加载JavaScript学习目标了解DOMContentLoaded为什么如此重要在DOMContentLoaded上设置一个事件... DOMContentLoaded事件是浏览器的内置方法,用于指示何时将页面的html加载到DOM中。 无法操纵尚未呈现HTM
在文档加载时加载JavaScript 学习目标 了解DOMContentLoaded为什么如此重要 在DOMContentLoaded上设置一个... DOMContentLoaded事件是浏览器的内置方法,用于指示何时将页面的html加载到DOM中。 无法操纵尚未呈现HTM
形象的描述了async与defer的区别,...defer是延迟执行,在浏览器看起来的效果像是将脚本放在了 body后面一样(虽然按规范应该是在 DOMContentLoaded事件前,但实际上不同浏览器的优化效果不一样,也有可能在它后面)
当浏览器解析到这个节点时,发现它是一个js文件,那么浏览器会停止解析剩余的DOM节点,开始执行这个js(即angular.js),同时Angular会设置一个事件监听器来监听浏览器的DOMContentLoaded事件。当Angular监听到这个...
dom-loaded 检查何时加载DOM类似于`DOMContentLoaded`
3. 触发DOMContentLoaded事件 4. 注入5+ API 5. 触发plusready事件 这样导致5+ API生效时间比较延后,在html中引用js执行之后才能调用5+ API,通常采用以下代码调用5+ API: document.addEventListener('plusready'
WebKit 照片浏览器:在 WebKit 中使用现代 Web 技术展示...索引.js index.js充当应用程序的初始化脚本,其中画廊在document对象上的DOMContentLoaded事件上实例化。masonry-gallery.js masonry-gallery.js定义了一个类
jquery的ready()实现的是 DOMContentLoaded 事件,DOMContentLoaded与window load事件的区别 简单的说ready()是在文档加载完成就会触发,此时图片等资源可能还没有完全加载, load是在所有资源都加载完成后才会触发 看...
dom01元素位置测试client:都是相对于视口。 getBoundingClientRect()它们的值是相对于视口的,而不是绝对的。... DOMContentLoaded事件:等待dom文档加载完成el.offsetTop:相对于父元素的转换量(父元素为r
从ES6模块导入并在DOMContentLoaded事件之后初始化。 < script type =" module " > import { panzoom } from 'https://github.com/cmorillas/panzoom/src/panzoom.js' ; document . addEventListener ( ...