Document directory
- I. Prototype
- Ii. jQuery
- 3. Moontools
- 4. Dojo
- V. YUI
- Vi. EXT
- Summary
In practical applications, we often encounter such scenarios, when the page is loaded, do some things: Binding events, Dom operations, and some nodes. The onload event of window is commonly used, and the actual effect of this event is: when the page parsing/DOM tree is complete, it is triggered only after downloading all the resources in fragments, scripts, style sheets, and IFRAME. This is a little too late for many practical applications, which affects the user experience. To solve this problem, a domcontentloaded method is added to ff. Compared with onload, this method is triggered earlier. It is triggered after the DOM content of the page is loaded, instead of waiting for loading other resources. The WebKit engine has introduced this event since version 525 (WebKit nightly 1/2008: 525 +). Opera also includes this method. So far, mainstream ie still has no meaning to add. Although IE does not exist, there is always a solution. The following compares the compatibility version Implementation Solutions of several mainstream frameworks for this event. The frameworks involved include:
- Prototype
- JQeury
- Moontools
- Dojo
- Yui
- Ext
I. Prototype
Implementation Code
(function() {/* Support for the DOMContentLoaded event is based on work by Dan Webb,Matthias Miller, Dean Edwards and John Resig. */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=//:><\/script>");$("__onDOMContentLoaded").onreadystatechange = function() {if (this.readyState == "complete") {this.onreadystatechange = null;fireContentLoadedEvent();}};}})();
The implementation idea is as follows:
- If it is webkit, The readyState attribute of the document will be poll. If the value of this attribute is loaded or complete, the DOMContentLoaded event will be triggered. To be safe, register the event to window. onload.
- If it is FF, The DOMContentLoaded event is directly registered.
- For IE, use document. write to add a script element to the page and set the defer attribute. Finally, the script is loaded as a DOMContentLoaded event.
There are two main problems with this implementation method: first, using document. when the page contains IFRAME, the method of writing scripts and setting defer will wait until the content in IFRAME is loaded, which is not much different from onload; 2. The domcontentloaded method is introduced in WebKit Versions later than 525. Therefore, in these versions, it can be optimized without polling.
Ii. jquery
function bindReady(){if ( readyBound ) return;readyBound = true;// Mozilla, Opera and webkit nightlies currently support this eventif ( document.addEventListener ) {// Use the handy event callbackdocument.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 iframesdocument.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 readyif ( document.documentElement.doScroll && typeof window.frameElement === "undefined" ) (function(){if ( jQuery.isReady ) return;try {// If IE is used, use the trick by Diego Perini// http://javascript.nwbox.com/IEContentLoaded/document.documentElement.doScroll("left");} catch( error ) {setTimeout( arguments.callee, 0 );return;}// and execute any waiting functionsjQuery.ready();})();}// A fallback to window.onload, that will always workjQuery.event.add( window, "load", jQuery.ready );}
The implementation idea is as follows:
- Similarly, Webkit and Firefox are used to directly register the DOMContentLoaded event. However, because Webkit is introduced in Versions later than 525, there is a compatibility risk.
- For IE, first register the onreadystatechange event of the document. After testing, this method is equivalent to window. onload and will still be triggered after all resources are downloaded.
- After that, if it is IE and the page is not in iframe, The doScroll method of documentElement is continuously called through setTiemout until the call is successful, and DOMContentLoaded is triggered.
JQuery uses a new method for IE solutions, which is derived from http://javascript.nwbox.com/iecontentloaded /. In IE, some DOM methods can be called only after DOM Parsing is complete. doScroll is such a method, in turn, when doScroll can be called, that is, when DOM Parsing is completed, it is consistent with the document in prototype. compared with write, this solution can solve the problem that iframe is invalid on the page. In addition, jQuery seems worried that this method will fail when the page is in iframe, so the implementation code makes a judgment. If it is in iframe, it is implemented through onreadystatechange of document, otherwise, it is implemented through doScroll. However, after testing, even in iframe, doScroll is still valid.
3. moontools
(function(){var domready = function(){if (Browser.loaded) return;Browser.loaded = true;window.fireEvent('domready');document.fireEvent('domready');};if (Browser.Engine.trident){var temp = document.createElement('div');(function(){($try(function(){temp.doScroll('left');return $(temp).inject(document.body).set('html', 'temp').dispose();})) ? domready() : arguments.callee.delay(50);})();} else if (Browser.Engine.webkit && Browser.Engine.version < 525){(function(){(['loaded', 'complete'].contains(document.readyState)) ? domready() : arguments.callee.delay(50);})();} else {window.addEvent('load', domready);document.addEvent('DOMContentLoaded', domready);}})();
The implementation idea is as follows:
- If it is IE, use the doScroll method.
- If it is a Webkit earlier than version 525, it is implemented by polling document. readyState.
- Others (FF/Webkit high edition/Opera) register the DOMContentLoaded event directly.
The Moontools Implementation Scheme prototype and jQeury are integrated, and the webkit version judgment makes the scheme more robust. In the implementation of doScroll, compared with jQuery, a new div element is created and destroyed after use, while jQuery directly uses the doScroll of documentElement for detection, it is simpler and more efficient.
4. dojo
// START DOMContentLoaded// Mozilla and Opera 9 expose the event we could useif(document.addEventListener){// NOTE:// due to a threading issue in Firefox 2.0, we can't enable// DOMContentLoaded on that platform. For more information, see:// http://trac.dojotoolkit.org/ticket/1704if(dojo.isOpera || dojo.isFF >= 3 || (dojo.isMoz && dojo.config.enableMozDomContentLoaded === true)){document.addEventListener("DOMContentLoaded", dojo._loadInit, null);}// mainly for Opera 8.5, won't be fired if DOMContentLoaded fired already.// also used for Mozilla because of trac #1640window.addEventListener("load", dojo._loadInit, null);}if(dojo.isAIR){window.addEventListener("load", dojo._loadInit, null);}else if(/(WebKit|khtml)/i.test(navigator.userAgent)){ // sniffdojo._khtmlTimer = setInterval(function(){if(/loaded|complete/.test(document.readyState)){dojo._loadInit(); // call the onload handler}}, 10);}// END DOMContentLoaded}(function(){var _w = window;var _handleNodeEvent = function(/*String*/evtName, /*Function*/fp){// summary:// non-destructively adds the specified function to the node's// evtName handler.// evtName: should be in the form "onclick" for "onclick" handlers.// Make sure you pass in the "on" part.var oldHandler = _w[evtName] || function(){};_w[evtName] = function(){fp.apply(_w, arguments);oldHandler.apply(_w, arguments);};};if(dojo.isIE){// for Internet Explorer. readyState will not be achieved on init// call, but dojo doesn't need it however, we'll include it// because we don't know if there are other functions added that// might. Note that this has changed because the build process// strips all comments -- including conditional ones.if(!dojo.config.afterOnLoad){document.write('<scr'+'ipt defer="" src="//:" +="" onreadystatechange="if(this.readyState==\'complete\'){' + dojo._scopeName + '._loadInit();}">'+ '</scr'+'ipt>');}try{document.namespaces.add("v","urn:schemas-microsoft-com:vml");document.createStyleSheet().addRule("v\\:*", "behavior:url(#default#VML)");}catch(e){}}// FIXME: dojo.unloaded requires dojo scope, so using anon function wrapper._handleNodeEvent("onbeforeunload", function() { dojo.unloaded(); });_handleNodeEvent("onunload", function() { dojo.windowUnloaded(); });})();
The implementation idea is as follows:
- If it is Opera or FF3 or later, the DOMContentLoaded event is directly registered. For the sake of security, the window. onload event is also registered.
- Webkit is implemented by polling document. readyState.
- If it is Air, only the widnow. onload event is registered.
- For IE, the script with the defer attribute is written on the previous page and Its onreadystatechange event is registered.
The implementation scheme of Dojo in IE cannot solve the problem of iframe. Because there is a very strange Bug in FF2, The DOMContentLoaded event is used only in FF3 and later versions by default, at the same time, a configuration-dojo. config. enablejavasdomcontentloaded. If you set this configuration to true under FF, DOMContentLoaded will still be used for implementation, which fully considers the flexibility. The implementation of webkit is as optimized as prototype.
V. Yui
/*! DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller */// Internet Explorer: use the readyState of a defered script.// This isolates what appears to be a safe moment to manipulate// the DOM prior to when the document's readyState suggests// it is safe to do so.if (EU.isIE) {// Process onAvailable/onContentReady items when the// DOM is ready.YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event, true);var n = document.createElement('p');EU._dri = setInterval(function() {try {// throws an error if doc is not readyn.doScroll('left');clearInterval(EU._dri);EU._dri = null;EU._ready();n = null;} catch (ex) {}}, EU.POLL_INTERVAL);// The document's readyState in Safari currently will// change to loaded/complete before images are loaded.} else if (EU.webkit && EU.webkit < 525) {EU._dri = setInterval(function() {var rs=document.readyState;if ("loaded" == rs || "complete" == rs) {clearInterval(EU._dri);EU._dri = null;EU._ready();}}, EU.POLL_INTERVAL);// FireFox and Opera: These browsers provide a event for this// moment. The latest WebKit releases now support this event.} else {EU._simpleAdd(document, "DOMContentLoaded", EU._ready);}/////////////////////////////////////////////////////////////EU._simpleAdd(window, "load", EU._load);EU._simpleAdd(window, "unload", EU._unload);EU._tryPreloadAttach();})();
Similar to Moontools
Vi. ext
function initDocReady(){var COMPLETE = "complete";docReadyEvent = new Ext.util.Event();if (Ext.isGecko || Ext.isOpera) {DOC.addEventListener(DOMCONTENTLOADED, fireDocReady, false);} else if (Ext.isIE){DOC.write("<s"+'cript id=" + IEDEFERED + " defer="defer" src="/%27+%27/:"></s"+'cript>");DOC.getElementById(IEDEFERED).onreadystatechange = function(){if(this.readyState == COMPLETE){fireDocReady();}};} else if (Ext.isWebKit){docReadyProcId = setInterval(function(){if(DOC.readyState == COMPLETE) {fireDocReady();}}, 10);}// no matter what, make sure it fires on loadE.on(WINDOW, "load", fireDocReady);};
The implementation idea is the same as that of Dojo.
Summary
Summarize the practices of major frameworks and write the following version. It is mainly to optimize as much as possible and take into account the Bug in FF2, and provide whether to use the DOMContentLoaded Switch configuration.
/** Register the browser's DOMContentLoaded event * @ param {Function} onready [required] Function to be executed when the DOMContentLoaded event is triggered * @ param {Object} config [Optional] configuration item * /function onDOMContentLoaded (onready, config) {// check related objects in the browser, which is not implemented in order to save code, but must be implemented in actual use. // Var Browser ={}; // set whether to use DOMContentLoaded in FF (A Bug exists in the specific scenario of FF2) this. conf = {enabledomaindomready: true}; if (config) for (var p in config) this. conf [p] = config [p]; var isReady = false; function doReady () {if (isReady) return; // ensure that onready is executed only once; onready ();}/* IE */if (Browser. ie) {(function () {if (isReady) return; try using document.doc umentElement. doScroll ("left");} catch (error) {setTimeout (argumen Ts. callee, 0); return;} doReady () ;}) (); window. attachEvent ('onload', doReady);}/* Webkit */else if (Browser. webkit & Browser. version <525) {(function () {if (isReady) return; if (/loaded | complete /. test (document. readyState) doReady (); elsesetTimeout (arguments. callee, 0) ;}) (); window. addEventListener ('load', doReady, false);}/* FF Opera High Version webkit others */else {if (! Browser. ff | Browser. version! = 2 | this. conf. enabledomaindomready) document. addEventListener ("DOMContentLoaded", function () {document. removeEventListener ("DOMContentLoaded", arguments. callee, false); doReady () ;}, false); window. addEventListener ('load', doReady, false );}}
Source: Implementation of DOMContentLoaded events in mainstream frameworks