一、在介绍DomReady之前,先了解下相关的知识

1、HTML是一种标记语言,告诉我们这页面里面有什么内容,但是行为交互则要通过DOM操作来实现,但是注意:不要把尖括号里面的内容看作是DOM!

2、HTML是要通过浏览器解析之后才会转换成为DOM节点

一般地,但我们向浏览器中输入一个地址,开始加载页面到我们看到页面的内容为止,这期间就有一个DOM节点构建的过程(浏览器将HTML标签转换为DOM节点)。

当前页面上的所有的HTML标签都转换成DOM节点,这就叫DOM树建完,简称为DOMReady.

3、浏览器是自上向下,从左往右,HTML字符串标签一个一个的读入,页面上会有很多的标签,响相应的会生成很多的对应的DOM,每种标签对应的规则不一样,有的标签下面可以添加任意的HTML标签,有的标签下面却只能加规定的标签,如<tr>标签下面就只能是<td>或者<th>如果你加其他的标签比如<span>,浏览器则不会解释这个标签,又比如<option>下面规定只能加文本。

4、一般的HTML标签的都转换成DOM节点的速度很快,但是有写却很慢,比如图片,外部脚本文件,外部css样式表,等的文件,当浏览器解释到这一类的标签,回去指定的路径加载对应的文件,

这里注意JS文件:浏览器下载完指定的脚本文件后,首先会执行当前脚本文件,等执行完道歉脚本文件后,才会解析下一个标签,当当前脚本文件非常大的时候,浏览器就会产生"堵塞"现象。

5、因为浏览器渲染引擎是单线程的,如果头部脚本文件过多过大,会产生"白屏"现象,所以为了防止这种情况,我们应该将所有的脚本文件都放到</body>标签之前,这一点在雅虎军规中也有提到。

6、此外, style标签与link标签,它们在加载样式文件时是不会堵塞,但它们一旦异步加载好,就立即开始渲染已经构建好的元素节点们, 这可能会引起reflow, 这也影响速度.

7、另一个影响DOM构建的标签是iframe,他不会堵塞Dom构建,但是它会在加载DOM时和其他标签争抢资源(因为iframe会发送http请求,但是http请求有限),们经常看到一些新闻网,上面会挂许多iframe广告, 这些页面一开始加载时就很卡,也是这缘故.

总结:上面的种种原因都会影响到DOM的构建,所以我们贸然的使用getElementById,ByTageName等等方法获取页面的元素时,很可能页面上的HTML标签还没有转换成为DOM节点,所以就会报null的错误

二、使用DomReady机制解决因DOM解析未完成前使用document.getElementById获取报null错误的问题

1、在早期的浏览器中,提供了一个window.onload方法,这个方法会在浏览器加载完所有的文件(包括图片、脚本文件、样式文件),且HTML标签都转换成为DOM节点是,会被触发,但是这个方法在执行时间上有点晚,如果图片很多,那么你懂得额!!!!!

2、在标签浏览器, W3C终于绅士地提供了一个DOMContentLoaded事件;在旧式IE下,也可以勉强使用onreadystatechange事件模拟, 直接某一天,有个外国大牛发掘出doScroll这个伟大的hack, 它让我们在IE下更接近DOMContentLoaded的效果

<script>
/**
*方法作用:DomReady其实是一种名为"DomContentLoaded"事件的名称,不过由于框架的需要,
它与真正的DomContentLoaded有区别,在旧的JS书籍中m都会让我们把Js函数写到window.onload函数中,
防止Dom树还没有建好,就对节点进行操作,产生错误。而对框架来说,越早介入对Dom的干涉越好,
如果要进行特征侦测之类的。DomReady还可以满足用户提前绑定事件的需求,因为有时页面图片资源过多,
window.onload迟迟不能触发,这时若还没有绑定事件,用户点哪个按钮都没有反应。因此主流框架都引入domready机制,
并且废了很大的劲兼容很多的浏览器 readyState 属性返回当前文档的状态(载入中……)。
该属性返回以下值:
uninitialized - 还未开始载入
loading - 载入中
interactive - 已加载,文档与用户可以开始交互
complete - 载入完成 逻辑:
1、首先通过document.readyState判断DOM节点的加载情况,如果文档加载完成(HTML标签转换成DOM节点)document.readyState=complete
那么直接执行Dom.beforeReady()方法
2、如果文档没有加载完成,且浏览器是不是IE,那么
*/ var Dom = [];
Dom.isReady = false;//用于判断页面是否加在完毕
Dom.domReady = function (fn) {
if (Dom.isReady)
fn();
else
Dom.push(fn);
} //页面加载完毕(readyState="complete")立即执行当前函数
Dom.beforeReady = function () {
//通过isReady属性,控制beforeReady只执行一次
//通过判断document.body,确认文档是否加在完毕,否则循环每隔16ms,吊用自己
//上面的判断都通过后,循环执行Dom数组中的方法
if(!Dom.isReady){
if(!document.body){
setTimeout(arguments.callee,16);
}
Dom.isReady=true;
for(var i=0,fn;fn=Dom[i];i++){
fn();//虽然不太合理,但是在Javascript中这是可行的
}
}
} /**
* 开始初始化domReady函数,判定页面加载在情况 start
*/
if (!document.readyState) {
//处理在firefox3.6之前,不存在readyState属性的bug http://www.cnblogs.com/rubylouvre/archive/2012/12/18/2822912.html
var readyState = document.readyState = document.body ? "complete" : "loading";
}
if (document.readyState === "complete") {
Dom.beforeReady();
}
else if (-[1,]) {//如果浏览器不是IE,那么给document绑定DOMContentLoaded事件
//addEventListener() 方法用于向指定元素添加事件句柄。
//提示: 使用 removeEventListener() 方法来移除 addEventListener() 方法添加的事件句柄
//注意: Internet Explorer 8 及更早IE版本不支持 addEventListener() 方法,,Opera 7.0 及 Opera 更早版本也不支持。
// 但是,对于这些不支持该函数的浏览器,你可以使用 attachEvent() 方法来添加事件句柄 (查看 "更多实例" 了解跨浏览器的解决方案)。
//removeEventListener(event,function,useCapture)
//event 必须。字符串,指定事件名。
//function 必须。指定要事件触发时执行的函数。
//useCapture 可选。布尔值,指定事件是否在捕获或冒泡阶段执行。 true - 事件句柄在捕获阶段执行 false- false- 默认。事件句柄在冒泡阶段执行
document.addEventListener("DOMContentLoaded", function () {
document.removeEventListener("DOMContentLoaded",arguments.callee, false);
Dom.beforeReady();
});
}
else {//IE的情况 //在IE下,使Dom.domReady先于window.onload执行
//1、在老版本IE中onreadystatechange事件会触发在window.onload之后
//2、当页面包含图片时,onreadystatechange事件会触发在window.onload之后(换言之,它只能正确地执行于页面不包含二进制资源或非常少或者被缓存时)
document.attachEvent("onreadystatechange", function() {
if ( document.readyState == "complete" ) {
document.detachEvent("onreadystatechange", arguments.callee );
Dom.beforeReady();
}
});
(function () {
// DOM树未创建完之前调用doScroll会抛出错误
var node = new Image();
try {
node.doScroll();
node = null;//防止IE内存泄漏
}
catch (e) {
//javascrpt最短时钟间隔为16ms,这里取64 http://blog.csdn.net/aimingoo/article/details/1451556
setTimeout(arguments.callee, 64);
return;
}
Dom.beforeReady();
})();
}
/**
* 开始初始化domReady函数,判定页面加载在情况 end
*/ window.onload = function(){
var p = document.createElement("p")
p.innerHTML = "window.onload"
document.body.appendChild(p);
};
Dom.domReady(function(){
var p = document.createElement("p")
p.innerHTML = "domReady1"
document.body.appendChild(p);
});
Dom.domReady(function(){
var p = document.createElement("p")
p.innerHTML = "domReady2"
document.body.appendChild(p);
});
</script>

Js框架设计之DomReady的更多相关文章

  1. js框架设计1.1命名空间笔记

    借到了司徒正美的写的js框架设计一书,司徒大神所著有些看不太懂,果然尚需循序渐进,稳扎js基础之中. 第一张开篇司徒阐述了种子模块的概念 种子模块亦为核心模块,框架最先执行模块,司徒见解应包含:对象扩 ...

  2. JS框架设计之对象数组化一种子模块

    类数组对象是一个很好的存储结构,但是功能太弱了,为了享受纯数组的哪些便捷的方法,使用前可以做下转换,通常可以使用$.slice.call()方法做转换,但是旧版本的IE下的HTMLCollection ...

  3. JS框架设计之主流框架的引入机制DomeReady一种子模块

    DomReady其实是一种名为"DomContentLoaded"事件的名称,不过由于框架的需要,它与真正的DomContentLoaded有区别,在旧的JS书籍中m都会让我们把J ...

  4. js框架设计1.4类型判断

    这篇司徒大神介绍了很多js的 不靠谱类型判断.篇幅也是第一篇中最常的 ,经阅读后,以后一定要用框架的自带的类型判断,万万不可随便乱用js原生判断.

  5. JS框架设计读书笔记之-节点模块

    节点的创建 浏览器提供了多种手段创建API,从流行程度依次是document.createElement.innerHTML.insertAdjacentHTML.createContextualFr ...

  6. JS框架设计读书笔记之-核心模块

    随笔记录一下读书心得 1. 框架模块-核心模块 该模块是框架最先执行的部分,jQuery与vue中都有初始化的代码. 模块的功能主要是:对象扩展.数组化.类型判定.事件绑定和解绑.无冲突处理.模块加载 ...

  7. JS框架设计之对象扩展一种子模块

    对象扩展 说完了,对象的创建(框架的命名空间的创建)以及如何解决多库之间的命名空间冲突问题之后,接下来,就是要扩展我们的对象,来对框架进行扩展,我们需要一种新功能,将新添加的功能整合到我们定义的对象中 ...

  8. JS框架设计之命名空间设计一种子模块

    命名空间 1.种子模块作为一个框架的最开始,除了负责初始化框架的最基础部分. 2.种子模块作为框架的最开始,那么什么是种子框架的最开始呢?答案是IIFE(立即调用函数表达式); IIFE(立即调用函数 ...

  9. js框架设计1.2对象扩展笔记

    需要一个新的功能添加到我们的命名空间上.这方法在JS中被叫做extend或者mixin,若是遍历属性用一下1.1代码,则会遍历不出原型方法,所以1.2介绍的是mass Framework里的mix方法 ...

随机推荐

  1. 编写高质量代码改善C#程序的157个建议——建议153:若抛出异常,则必须要注释

    建议153:若抛出异常,则必须要注释 有一种必须加注释的场景,即使异常.如果API抛出异常,则必须给出注释.调用者必须通过注释才能知道如何处理那些专有的异常.通常,即便良好的命名也不可能告诉我们方法会 ...

  2. Java多线程设计模式(三)

    目录(?)[-] Read-Wirte Lock Pattern Thread-Per-Message Pattern Worker Thread Pattern   Read-Wirte Lock ...

  3. 10、Semantic-UI之图片的使用

    10.1 图片的使用 定义有边框的图片样式 <img class="ui medium bordered image" src="../images/pic.png ...

  4. VCS简介

    VCS -Version Control System 版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统. 特征 1.记录文件的所有历史变化 2.随时可恢复到任何一个历史状 ...

  5. centos 6.5下安装mysql

    1.检测系统是否已经安装过mysql或其依赖,若已装过要先将其删除,否则第4步使用yum安装时会报错: 1 # yum list installed | grep mysql 2 mysql-libs ...

  6. C# WPF 开发随想

    最近项目遇到切换窗口的时候偶尔出现闪屏的问题,前前后后花了两天的时间还是没有找到问题所在,一部分一部分的注释代码,看逻辑,开布局,还是一无所获. 最后还是他人的提醒下,直接不切换窗口,在同一个窗口中布 ...

  7. 1. Python2 ,Python3区别

    Python2: 1. 源码都含有PHP,Java,C等语言的规范陋习. 2.重复代码比较多. Python3: 源码很规范,清晰,简单,符合Python的宗旨.

  8. IO模型《五》异步IO

    Linux下的asynchronous IO其实用得不多,从内核2.6版本才开始引入.先看一下它的流程: 用户进程发起read操作之后,立刻就可以开始去做其它的事.而另一方面,从kernel的角度,当 ...

  9. kali linux之Bdfproxy

    Bdfproxy(mitmproxy) 基于流量劫持动态注入shellcode(arp欺骗,dns欺骗,流氓ap) 步骤: 开启流量转发---------sysctl -w net.ipv4.ip_f ...

  10. 让子类使用父类的Logger

    参考博客:https://blog.csdn.net/zx1323/article/details/71262613 1.让子类使用父类的Logger,这是一种语法思路,可以减少代码臃肿. 2.使用的 ...