JS DOMReady事件的六种实现方法总结

在实际应用中,我们经常会遇到这样的场景,当页面加载完成后去做一些事情:绑定事件、DOM操作某些结点等。

原来比较常用的是window的onload 事件,而该事件的实际效果是:当页面解析/DOM树建立完成,并完成了诸如图片、脚本、样式表甚至是iframe中所有资源的下载后才触发的。

这对于很多实际的应用而言有点太“迟”了,比较影响用户体验。

为了解决这个问题,ff中便增加了一个DOMContentLoaded方法,与onload相比,该方法触发的时间更早,它是在页面的DOM内容加载完成后即触发,而无需等待其他资源的加载。

Webkit引擎从版本525(Webkit nightly 1/2008:525+)开始也引入了该事件,Opera中也包含该方法。到目前为止主流的IE仍然没有要添加的意思。

虽然IE下没有,但总是有解决办法的,下文对比了一下几大主流框架对于该事件的兼容性版本实现方案,涉及的框架包括:

1. Prototype
2. jQeury
3. moontools
4. dojo
5. yui
6. ext

一、Prototype

实现代码

(function() { var timer; function fireContentLoadedEvent() { if (document.loaded) return; if (timer) window.clearInterval(timer); document.fire("dom:loaded"); document.loaded = true; } if (document.addEventListener) { if (Prototype.Browser.WebKit) { timer = window.setInterval(function() { if (/loaded|complete/.test(document.readyState)) fireContentLoadedEvent(); }, 0); Event.observe(window, "load", fireContentLoadedEvent); } else { document.addEventListener("DOMContentLoaded", fireContentLoadedEvent, false); } } else { document.write("<"+"script id=__onDOMContentLoaded defer src=https://www.jb51.net//:><\/script>"); $("__onDOMContentLoaded").onreadystatechange = function() { if (this.readyState == "complete") { this.onreadystatechange = null; fireContentLoadedEvent(); } }; } })();

实现思路如下:

如果是webkit则轮询document的readyState属性,如果该属性的值为loaded或complete则触发DOMContentLoaded事件,为保险起见,将该事件注册到window.onload上。

如果是FF则直接注册DOMContentLoaded事件。

如果是IE则使用document.write往页面中加入一个script元素,并设置defer属性,最后是把该脚本的加载完成视作DOMContentLoaded事件来触发。

该实现方式的问题主要有两点:第一、通过document.write写script并设置defer的方法在页面包含iframe的情况下,会等到 iframe内的内容加载完后才触发,这与onload没有太大的区别;第二、Webkit在525以上的版本引入了DOMContentLoaded方法,因此在这些版本中无需再通过轮询来实现,可以优化。

二、jQuery

function bindReady(){ if ( readyBound ) return; readyBound = true; // Mozilla, Opera and webkit nightlies currently support this event if ( document.addEventListener ) { // Use the handy event callback document.addEventListener( "DOMContentLoaded", function(){ document.removeEventListener( "DOMContentLoaded", arguments.callee, false ); jQuery.ready(); }, false ); // If IE event model is used } else if ( document.attachEvent ) { // ensure firing before onload, // maybe late but safe also for iframes document.attachEvent("onreadystatechange", function(){ if ( document.readyState === "complete" ) { document.detachEvent( "onreadystatechange", arguments.callee ); jQuery.ready(); } }); // If IE and not an iframe // continually check to see if the document is ready if ( document.documentElement.doScroll && typeof window.frameElement === "undefined" ) (function(){ if ( jQuery.isReady ) return; try { // If IE is used, use the trick by Diego Perini // document.documentElement.doScroll("left"); } catch( error ) { setTimeout( arguments.callee, 0 ); return; } // and execute any waiting functions jQuery.ready(); })(); } // A fallback to window.onload, that will always work jQuery.event.add( window, "load", jQuery.ready ); }

实现思路如下:

将Webkit与Firefox同等对待,都是直接注册DOMContentLoaded事件,但是由于Webkit是在525以上版本才引入的,因此存在兼容性的隐患。

对于IE,首先注册document的onreadystatechange事件,经测试,该方式与window.onload相当,依然会等到所有资源下载完毕后才触发。

之后,判断如果是IE并且页面不在iframe当中,则通过setTiemout来不断的调用documentElement的doScroll方法,直到调用成功则

出触发DOMContentLoaded

jQuery对于IE的解决方案,使用了一种新的方法,该方法源自。它的原理是,在IE下,DOM的某些方法只有在DOM解析完成后才可以调用,doScroll就是这样一个方法,反过来当能调用doScroll的时候即是DOM解析完成之时,与prototype中的document.write相比,该方案可以解决页面有iframe时失效的问题。此外,jQuery 似乎担心当页面处于iframe中时,该方法会失效,因此实现代码中做了判断,如果是在iframe中则通过document的 onreadystatechange来实现,否则通过doScroll来实现。不过经测试,即使是在iframe中,doScroll依然有效。

三、Moontools

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wzzggg.html