`
LiZn
  • 浏览: 9875 次
  • 性别: 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
分享到:
评论

相关推荐

    JS兼容所有浏览器的DOMContentLoaded事件

    主要介绍了JS兼容所有浏览器的DOMContentLoaded事件的相关资料,标准浏览器中,使用DOMContentLoaded事件即可实现我们的要求,注册事件处理函数也极为简单,感兴趣的朋友一起学习吧

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

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

    Javascript封装DOMContentLoaded事件实例

    主要介绍了Javascript封装DOMContentLoaded事件实例,DOMContentLoaded是FF,Opera 9的特有的Event, 当所有DOM解析完以后会触发这个事件,需要的朋友可以参考下

    JS、CSS以及img对DOMContentLoaded事件的影响

    最近在做性能有关的数据上报,发现了两个非常有意思的东西:Chrome开发者工具的Timeline分析面板,以及DOMContentLoaded事件。一个是强大的令人发指的性能分析工具,一个是重要的性能指标,于是就用Timeline对...

    littlepjs-document-onload-dc-web-120919

    在文档加载时加载JavaScript 学习目标 了解DOMContentLoaded为什么如此重要 在DOMContentLoaded上设置一个... DOMContentLoaded事件是浏览器的内置方法,用于指示何时将页面的html加载到DOM中。 无法操纵尚未呈现HTM

    somepjs-document-onload-dc-web-102819

    在文档加载时加载JavaScript 学习目标 了解DOMContentLoaded为什么如此重要 在DOMContentLoaded上设置一个... DOMContentLoaded事件是浏览器的内置方法,用于指示何时将页面的html加载到DOM中。 无法操纵尚未呈现HTM

    littlepjs-文档-加载-nyc01-seng-ft-042020

    在文档加载时加载JavaScript 学习目标 了解DOMContentLoaded为什么如此重要 在DOMContentLoaded上设置一个... DOMContentLoaded事件是浏览器的内置方法,用于指示何时将页面的html加载到DOM中。 无法操纵尚未呈现HTM

    littlepjs-文档-加载-nyc-web-080519

    在文档加载时加载JavaScript学习目标了解DOMContentLoaded为什么如此重要在DOMContentLoaded上设置一个事件... DOMContentLoaded事件是浏览器的内置方法,用于指示何时将页面的html加载到DOM中。 无法操纵尚未呈现HTM

    fewpjs-document-onload-rcdd_202104_tur_few

    在文档加载时加载JavaScript 学习目标 了解DOMContentLoaded为什么如此重要 在DOMContentLoaded上设置一个... DOMContentLoaded事件是浏览器的内置方法,用于指示何时将页面的html加载到DOM中。 无法操纵尚未呈现HTM

    async与defer的区别

    形象的描述了async与defer的区别,...defer是延迟执行,在浏览器看起来的效果像是将脚本放在了 body后面一样(虽然按规范应该是在 DOMContentLoaded事件前,但实际上不同浏览器的优化效果不一样,也有可能在它后面)

    AngularJS 执行流程详细介绍

    当浏览器解析到这个节点时,发现它是一个js文件,那么浏览器会停止解析剩余的DOM节点,开始执行这个js(即angular.js),同时Angular会设置一个事件监听器来监听浏览器的DOMContentLoaded事件。当Angular监听到这个...

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

    dom-loaded 检查何时加载DOM类似于`DOMContentLoaded`

    关于HTML5+ API plusready的兼容问题

    3. 触发DOMContentLoaded事件 4. 注入5+ API 5. 触发plusready事件 这样导致5+ API生效时间比较延后,在html中引用js执行之后才能调用5+ API,通常采用以下代码调用5+ API: document.addEventListener('plusready'

    WebKitPhotoBrowser:WebKit 照片浏览器

    WebKit 照片浏览器:在 WebKit 中使用现代 Web 技术展示...索引.js index.js充当应用程序的初始化脚本,其中画廊在document对象上的DOMContentLoaded事件上实例化。masonry-gallery.js masonry-gallery.js定义了一个类

    jquery中ready()函数执行的时机和window的load事件比较

    jquery的ready()实现的是 DOMContentLoaded 事件,DOMContentLoaded与window load事件的区别 简单的说ready()是在文档加载完成就会触发,此时图片等资源可能还没有完全加载, load是在所有资源都加载完成后才会触发 看...

    dom

    dom01元素位置测试client:都是相对于视口。 getBoundingClientRect()它们的值是相对于视口的,而不是绝对的。... DOMContentLoaded事件:等待dom文档加载完成el.offsetTop:相对于父元素的转换量(父元素为r

    panzoom:用于平移和缩放元素的库

    从ES6模块导入并在DOMContentLoaded事件之后初始化。 &lt; script type =" module " &gt; import { panzoom } from 'https://github.com/cmorillas/panzoom/src/panzoom.js' ; document . addEventListener ( ...

Global site tag (gtag.js) - Google Analytics