`
LiZn
  • 浏览: 10275 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
最近访客 更多访客>>
社区版块
存档分类
最新评论

跨浏览器的DOMContentLoaded事件

阅读更多

原文地址: 跨浏览器的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的源码,看完了再写篇读后感-。-

 

本博客文章由LiZn创作或分享,以创作公用CC 姓名标示-非商业性-相同方式分享 3.0 Unported 授权条款共享。 
转载请注明 转自: 跨浏览器的DOMContentLoaded事件 
希望本文能够对你有所帮助,欢迎留言讨论,如果你喜欢本站文章,可以使用该 RSS订阅地址来订阅本站。

 

2
0
分享到:
评论

相关推荐

    snack:一个小型的、跨浏览器的 JavaScript 库

    带有多个构建版本(QSA、 、 、 ) 几种元素方法用于添加更多元素方法的 API活动跨浏览器 DOMContentLoaded (domready) 跨浏览器 DOM 事件事件委托(有或没有选择器引擎)发布/订阅用于应用程序通信的发布者对象...

    domloaded检查何时加载DOM类似于DOMContentLoaded

    这个库通常用于那些希望避免直接使用原生事件的项目,因为它提供了更现代和一致的跨浏览器解决方案。Sindre Sorhus是一位知名的开源开发者,他的许多作品被广泛应用于JavaScript社区。 在实际应用中,“dom-loaded...

    浏览器兼容页面开发注意事项(javascript篇)_101028参考.pdf

    因此,跨浏览器的事件处理需要确保正确获取`event`对象,例如:`function handler(event) { var e = event || window.event; }`。 4. HTML对象的id作为对象名的问题:在IE中,可以直接通过id名访问对象,如`myObj =...

    js获取浏览器宽和高http://www.tiki-toki.com/

    如果博客中有更深入的讨论,比如跨浏览器兼容性问题、性能优化或特定场景下的应用,那么实际内容可能会包含更多细节和技巧。遗憾的是,没有链接无法访问到这些额外信息。在实际开发中,了解并应用这些基本概念是非常...

    比Jquery的document.ready更快的方法

    从给定的文件内容中,我们可以提炼出一些知识点,包括Jquery的$(document).ready()的替代方法...同时,为了兼容性考虑,需要通过判断浏览器是否支持addEventListener或动态插入script标签的方式来实现跨浏览器的支持。

    浏览器兼容页面开发注意事项(javascript篇)_101028分享.pdf

    为了确保代码在各种浏览器中都能正常工作,开发者需要了解这些差异,并使用条件语句或库(如jQuery、Prototype等)来编写跨浏览器的代码。此外,使用最新的Web标准和特性,以及对新特性进行适当的降级处理,也是保证...

    js 兼容火狐\360和IE的日历控件

    1. **跨浏览器JavaScript兼容性**: - 不同浏览器对JavaScript语法的支持程度不同,例如IE低版本不支持`let`和`const`等ES6特性,需要使用`var`声明变量。 - 使用`window.onload`或`DOMContentLoaded`确保页面加载...

    js代码 播放列表收缩展开 播放列表 左侧二级菜单 兼容主流浏览器

    在兼容性方面,由于项目明确指出兼容主流浏览器,开发者可能使用了跨浏览器的API和方法,比如使用`window.onload`或`DOMContentLoaded`事件来确保DOM加载完成后再执行JavaScript代码,避免了依赖于特定浏览器的行为...

    各浏览器对link标签onload/onreadystatechange事件支持的差异分析

    对于跨浏览器兼容性的需求,开发者需要了解这些差异,并可能需要采用其他策略来检测样式表的加载,比如使用MutationObserver API或者定时检查样式表的状态。另外,可以考虑使用`window.onload`或`DOMContentLoaded`...

    Javascript 事件 一览表

    六、跨浏览器事件兼容性 不同的浏览器可能对某些事件或事件处理方式支持程度不同,例如IE较早版本不支持DOM2级事件处理程序。为确保兼容性,开发者需使用工具库如jQuery,或者使用`attachEvent`等替代方法。 总结...

    MakeMediumReadableAgain浏览器扩展

    8. **跨浏览器兼容性**:虽然"Make Medium Readable Again"可能主要是为特定浏览器(如Chrome)设计的,但考虑到跨平台的兼容性,开发者可能也考虑了其他浏览器,如Firefox,可能需要处理不同浏览器间的API差异。...

    javascript获取当前页面可视高度和宽度及浏览器宽度和高度的函数.rar

    5. **跨浏览器兼容性**: 不同的浏览器对这些属性的支持可能存在差异,尤其是较旧版本的浏览器。在实际开发中,可能需要考虑使用条件语句或第三方库如jQuery来确保兼容性。 6. **应用场景**: - 响应式设计:根据...

    jQuery ready方法实现原理详解

    整个ready方法的核心就是使用JavaScript的事件监听机制来判断页面何时达到了可操作状态,并且在不同的浏览器环境和版本中做出相应的兼容处理,以实现jQuery ready()方法的跨浏览器一致性。通过这种方式,jQuery将...

    QQ在线客服悬挂右测带隐藏JS代码,兼容所有浏览器

    为了实现跨浏览器兼容性,开发者需要考虑不同的浏览器可能对CSS、DOM操作和事件处理有不同的实现。例如,IE(Internet Explorer)、Chrome、Firefox、Safari和Opera等浏览器可能在处理某些JS特性时存在差异。因此,...

    DIV向上滚动新闻,简洁JavaScript示例,高浏览器兼容性

    这非常重要,因为不同的浏览器可能对某些JavaScript特性或API的实现存在差异,良好的跨浏览器兼容性意味着更广泛的用户群体可以享受相同的用户体验。 在提供的压缩包文件中,"DIV向上滚动.html"可能是包含这个...

    浏览器兼容性问题

    - **解决方法**:建议使用`textContent`属性来代替`innerText`,以确保跨浏览器的兼容性。 ##### 3. CSS透明 - **问题描述**:不同浏览器对于CSS透明度的支持不同。 - **解决方法**:使用`opacity`属性,并为IE...

    解决firefox下resize事件无效问题

    在JavaScript编程中,`resize`事件是一个非常常用的功能,它允许开发者监听窗口或元素尺寸的变化。然而,在Firefox浏览器中,可能会...同时,记住在编写代码时始终考虑跨浏览器兼容性,以便为所有用户创建一致的体验。

    javascript事件大集合

    2. **DOM0级事件处理**:直接在JavaScript中为元素添加事件处理函数,这种方式仍存在跨浏览器兼容问题。 ```javascript var button = document.getElementById('myButton'); button.onclick = function() { alert...

    JS 实现web分页打印功能

    4. **跨浏览器兼容性**:尽管`Window.print()`方法在大多数现代浏览器中都得到了支持,但为了确保在旧版本浏览器中也能工作,我们需要进行兼容性测试,确保在IE、Firefox、Chrome、Safari等主流浏览器上均无问题。...

Global site tag (gtag.js) - Google Analytics