新的版本放弃使用document.write()(实际上我们依赖的是script标签的defer触发机制),主要基于如下几个理由:
- XHTML不支持document.write
- 当页面上的资源非常少时,会晚于window.onload
- document.write有时会覆写我们原有的DOM
- document.write生成的script不能通过内部函数移除
外国javascript高手Diego Perini于是发掘了doScroll这个方法。在IE下,doScroll方法存在于所有标签。但我搞来搞去,发现光是doScroll也不行,时不时就发现window.onload执行于domReady之前。只有结合onreadystatechange与doScroll这两个方法,我们才能在IE中搞出与标准浏览器相同的结果。因此你在jQuery,Prototype,swfobject,Ext等类库看到它们共同出现。而onreadystatechange其实也有些问题的,具体自己可能google一下,因此2006年左右实现domReady的代码基本依仗于document.write()。嗯,剩下的我就在代码间的注释中说明吧,这样更一目了解。
/* take from dom library version 1.0, inspired by jQuery Copyright 2010-2011 (2011.2.27更新) Dual licensed under the MIT or GPL Version 2 licenses. author "司徒正美" http://www.cnblogs.com/rubylouvre/ */ var dom = []; //用于判定页面是否加载完毕 dom.isReady = false; //用于添加要执行的函数 dom.ready = function(fn){ if ( dom.isReady ) { fn() } else { dom.push( fn ); } } //执行所有在window.onload之前放入的函数 dom.fireReady = function() { if ( !dom.isReady ) { if ( !document.body ) { return setTimeout( dom.fireReady, 16 ); } dom.isReady = 1; if ( dom.length ) { for(var i = 0, fn;fn = dom[i];i++) fn() } } } //开始初始化domReady函数,判定页面的加载情况 if ( document.readyState === "complete" ) { dom.fireReady(); }else if(-[1,] ){ document.addEventListener( "DOMContentLoaded", function() { document.removeEventListener( "DOMContentLoaded", arguments.callee , false ); dom.fireReady(); }, false ); }else { //当页面包含图片时,onreadystatechange事件会触发在window.onload之后, //换言之,它只能正确地执行于页面不包含二进制资源或非常少或者被缓存时 document.attachEvent("onreadystatechange", function() { if ( document.readyState == "complete" ) { document.detachEvent("onreadystatechange", arguments.callee ); dom.fireReady(); } }); (function(){ if ( dom.isReady ) { return; } //doScroll存在于所有标签而不管其是否支持滚动条 //这里如果用document.documentElement.doScroll(),我们需要判定其是否位于顶层document var node = new Image try { node.doScroll(); node = null//防止IE内存泄漏 } catch( e ) { //javascrpt最短时钟间隔为16ms,这里取其倍数 //http://blog.csdn.net/aimingoo/archive/2006/12/21/1451556.aspx setTimeout( arguments.callee, 64 ); return; } dom.fireReady(); })(); }