本文主要是介绍DOM Ready探究,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标志语言的标准编程接口。在网页上,组织页面(或文档)的对象被组织在一个树形结构中,用来表示文档中对象的标准模型就称为DOM。
我们常说的DOM分为DOM 1,DOM 2,DOM 3。DOM0实际上是不存在的,而它实际上是在IE 4时代出现的DHTML。再具体来说,DOM 1包括DOM Core(核心)、DOM HTML(针对HTML)。DOM 2包括DOM Views(视图)、DOM Event(事件)、DOM Style(基于CSS的样式)、DOM Traversal and Range(遍历和范围)。DOM 3包括 DOM Load and Save(模块加载和存储)、DOM Validation(验证)。
首先,我们举一个例子:
在这段代码中,我们通过获取id为content的h1标签来给它添加了文字的颜色,我们来看看效果:
效果并没有实现,而且还有报错:
这是为什么呢?首先我们进入了理解的盲区,我们错把HTML中的元素理解成为了DOM节点,而两者是有本质区别的。
在此我们先来说说浏览器渲染引擎的基本流程:
一,解析HTML,构建DOM树;————构建DOM节点
二,构建渲染树;——————————解析样式信息
三,布局渲染树;——————————布局DOM节点
四,绘制渲染树;——————————绘制DOM节点
指得一提的是在渲染的过程中外部资源始终都在加载。
这里找到一张webkit引擎的主要渲染流程图:
其实说这些就是为了便于理解为什么在上边的demo中会报错。DOM树的建立是在HTML文档加载之前,所以根本获取不到节点。
那么重点终于来了。我们如何解决这个问题?
一,把JS代码写在HTML文档最后。
好吧,第一种方法永远是最傻的。道理很简单,在较大的项目中需要多个JS代码植入,都写在下面岂不乱哉。
二,setTimeout()
这个很好理解,就是强行加入一个人为设定的时间。显然,这样做不合理且效率低。
三,使用window.onload
window.onload指的就是在HTML文档加载完之后再触发事件,这样就会相对舒服的避免了找不到对象的问题。但是,我们多思考一些,文档加载完?在前文中提到了外部资源始终都在加载,如果网速不给力、外部资源过多那很有可能我们在window.onload中写的所有所有所有代码都不会生效。这个问题很严重,于是第三种方法应运而生。
四,DOM Ready
英雄总是最后一个登场~ 首先上代码
<script>function myReady(fn){ //fn就是以后的回调函数// 对于现代浏览器,对DOMContentLoaded事件的处理方式采用的是标准的事件绑定方式if(document.addEventListener){document.addEventListener("DOMContentLoaded", fn, false); //通过绑定事件来侦测DOMReady,冒泡阶段捕获}else{IEContentLoaded(fn);}// IE模拟DOMCOntentLoadedfunction IEContentLoaded(fn){var d = window.document;var done = false;// 定义保证只执行一次用户回调的init()函数var init = function(){if(!done){done = true;fn();}};//侦测DOMReady并立即调用回掉函数方法(function(){try{// DOM 树未创建前调用doScroll会抛出错误d.documentElement.doScroll("left"); //如果DOM树没创建完就会抛出错误}catch(e){//延迟再试一次setTimeout(arguments.callee, 50);return;}// 没有错误就表示DOM树创建完毕,然后立马执行回掉函数init();})();// 监听document的加载状态d.onreadystatechange = function(){// 如果用户实在domReady之后绑定的函数,就立即执行if(d.readyState == "complete"){d.onreadystatechange = null; //清除掉init();}}}}
注释写的很清楚,主要再来说一下思路:使用DOM Ready的关键是DOMContentLoaded事件。这个事件是用来判断DOM树是否加载完,就是解析HTML的第一步,如果加载完成就立刻绑定事件到元素。
做好完美从来都不容易。定义了IEContentLoad()函数就是为了解决IE无法识别该事件的问题。思路是这样的:首先,能够实现效果的核心是利用IE中的documntElement.doScroll("left")方法来判断DOM树是否创建完毕。
第一步,定义init()回调函数,保证在DOM Ready后只执行一次。
第二步,定义了onreadystatechange()函数来监听document的加载状态(注:代码中将document存在了变量d中)。通过if语句判断document是否加载完成。这里利用readState方法,判断其值是否为complete。这时候将onreadystatechange事件清除掉,因为每当 readyState 改变时,就会触发 onreadystatechange 事件,这里涉及到Ajax的相关知识。之后再执行init()完成document的加载判定。
最后一步,定义一个自调函数来解决如果document加载的状态未就绪如何侦测到DOM Ready并立即调用回调函数。这里就利用到了documntElement.doScroll("left")方法在DOM树没加载完时会抛出错误的特点(注:left是随便传的),配合try...catch语句再实现延迟调用。延迟调用这里利用到了arguments.callee属性来使这个匿名函数实现调用。最后用return;实现递归。直到没有错误时就确保了了DOM树创立完毕并立刻执行回调。
OK~解释了这么多我们来看看效果。依然是最初的那个demo,我们来试一试:
使用我们的函数:
效果:
Bingo~达到了我们的效果~
我们写一个测试实施效果~:
HTML代码:
<body><div id="show"></div><div><img src="1.jpg" alt=""><img src="2.jpg" alt=""><img src="3.jpg" alt=""><img src="4.jpg" alt=""><img src="5.jpg" alt=""><img src="6.jpg" alt=""></div>
</body>
JS代码:
var time1 = null;
var time2 = null;myReady(function(){var msgBox = document.getElementById("show");var imgs = document.getElementsByTagName("img");msgBox.innerHTML += "DOM加载完成</br>";time1 = new Date().getTime();msgBox.innerHTML += "时间:" + time1 + "</br>";});window.onload = function(){var msgBox = document.getElementById("show");var imgs = document.getElementsByTagName("img");msgBox.innerHTML += "window.onload加载完成</br>";time2 = new Date().getTime();msgBox.innerHTML += "时间:" + time2 + "</br>";msgBox.innerHTML += "DOM Ready比window.onload快" + (time2 - time1) + "毫秒</br>";}
显而易见的结果~
最后,附上找到的jquery的DOM Ready方法:
function jQuery(a,c) {if ( a && a.constructor == Function && jQuery.fn.ready ){return jQuery(document).ready(a);}}jQuery.fn.extend({ready: function(f) {if ( jQuery.isReady )f.apply( document );else {jQuery.readyList.push( f );} return this;}});jQuery.extend({isReady: false,readyList: [],ready: function() {if ( !jQuery.isReady ) {jQuery.isReady = true;if ( jQuery.readyList ) {for ( var i = 0; i < jQuery.readyList.length; i++ )jQuery.readyList[i].apply( document );jQuery.readyList = null;}}}});new function(){if ( jQuery.browser.mozilla || jQuery.browser.opera ) {document.addEventListener( "DOMContentLoaded", jQuery.ready, false );} else if ( jQuery.browser.msie ) {document.write("<scr" + "ipt id=__ie_init defer=true " + "src=//:><\/script>");var script = document.getElementById("__ie_init");script.onreadystatechange = function() {if ( this.readyState == "complete" )jQuery.ready();};script = null;} else if ( jQuery.browser.safari ) {jQuery.safariTimer = setInterval(function(){if ( document.readyState == "loaded" || document.readyState == "complete" ) {clearInterval( jQuery.safariTimer );jQuery.safariTimer = null;jQuery.ready();}}, 10);} jQuery.event.add( window, "load", jQuery.ready ); }
这篇关于DOM Ready探究的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!