之前经由历程深切进修DOM的相干学问,看了慕课网DOM探究之基础详解篇这个视频(在近来看第三遍的时刻,预备纪录一点东西,算是对本身进修的一点总结),对DOM的邃晓又详细了一步,因为DOM底本就是一个笼统和观点性的东西,每深切一步相识,在脑中就会轻微详细一点,经由历程此次的对DOM的体系进修,对DOM有一个比较深入的邃晓,邃晓了DOM在JavaScript这门言语中无足轻重的职位,相识了DOm的生长汗青,也让我邃晓了存在浏览器浏览器兼容性的汗青缘由,对DOM的组织有了进一步的认知,对DOM的一些API也越发熟习,对照较笼统和观点性的DOM认知轻微详细了一些。下面就是本身深切进修DOM这门课程整顿的一些笔记,大部份来自进修中查阅的材料以及视频中先生讲的一些关键性学问点,固然也不可或缺的有本身的一些纪录和邃晓。
原文收录在我的 GitHub博客 (https://github.com/jawil/blog) ,喜好的可以关注最新动态,人人一同多交流进修,共同进步,以进修者的身份写博客,纪录点滴。
文章稍长,本文只叙述DOM基础观点,不触及DOM的一些事宜道理机制,页面元素的操纵和常常运用API的解说以及兼容性事项,所以观点性东西比较多,轻微有点笼统,个中有笔记来大部份来自先生的口述,另有一部份是查阅的文档,末了有一部份是本身的纪录和邃晓。
经由历程document.createElement("p")建立一个p元素一共溯寻了7层原型链,你晓得吗?
进修视频地点:DOM探究之基础详解篇,先生讲的很好,有兴致的可以连系视频进修一下,发起看完视频再看笔记,加深印象,你会受益不浅。
1、什么是DOM?
DOM,文档对象模子(Document Object Model)。DOM是 W3C(万维网同盟)的范例,DOM定义了接见HTML和XML文档的范例。在W3C的范例中,DOM是独于平台和言语的接口,它许可顺序和剧本动态地接见和更新文档的内容、组织和款式。
W3C DOM由以下三部份组成:
中心DOM – 针对任何组织化文档的范例模子
XML DOM – 针对 XML 文档的范例模子
HTML DOM – 针对 HTML 文档的范例模子
DOM(文档对象模子)是针对xml经由扩大用于html的运用顺序编程接口,我们又叫API。DOM把全部页面映照为一个多层的节点组织,html或xml页面中的每一个组成部份都是某种范例的节点,这些节点又包括着差别范例的数据。
<img width=”50%” src=”” target=”_blank”>http://ww1.sinaimg.cn/large/a…
2、DOM的职位
我们晓得,一个网页是由html来搭建组织的,经由历程css来定义网页的款式,而JavaScript给予了页面的行动,经由历程它我们可以与页面举行交互,完成页面的动画效果等等。那javascript终究经由历程什么来完成的呢?经由历程ECMAScript这个范例,我们可以编写顺序让浏览器来剖析,运用ECMAScript,我们可以经由历程BOM对象(即browser object model)来操纵浏览器窗口、浏览器导航对象(navigator)、屏幕分辨率(screen)、浏览器汗青(history)、cookie等等。但这个经由历程BOM来完成的交互远远不够。要完成页面的动态交互和效果,操纵html才是中心。那怎样操纵html呢?对,就是DOM,简朴的说,DOM给我们供应了用顺序来动态控制html的接口,也就是早期的DHTMl的观点。因此,DOM处在javascript给予html具有动态交互和效果的才的中心职位上。
<img width=”50%” src=”” target=”_blank”>http://ww1.sinaimg.cn/large/a…
3、DOM的生长-DOM0、DOM1、DOM2、DOM3的辨别
3.1、DOM0
JavaScript在早期版本中供应了查询和操纵Web文档的内容API(如:图象和表单),在JavaScript中定义了定义了’images’、’forms’等,因此我们可以像下如许接见第一张图片或名为“user”的表单:
document.images[0]document.forms['user']
这实际上是未形成范例的试验性子的初级阶段的DOM,如今习惯上被称为DOM0,即:第0级DOM。因为DOM0在W3C举行标预备化之前涌现,还处于未形成范例的早期阶段,这时候Netscape和Microsoft各自推出本身的第四代浏览器,自此DOM遍最早出种种题目。
3.2、DOM0与DHTML
Netscape Navigator 4和IE4离别宣布于1997年的6月和10月,这两种浏览器都大幅扩大了DOM,使JavaScript的功用大大增添,而此时也最早涌现一个新名词:DHTML。
DHTML是Dynamic HTML(动态HTML)的简称。DHTML并不是一项新手艺,而是将HTML、CSS、JavaScript手艺组合的一种形貌。即:
运用HTML把网页标记为种种元素
运用CSS设置元素款式及其显现位置
运用JavaScript操控页面元素和款式
运用DHTML,看起来可以很随意马虎的控制页面元素,并完成一此底本很庞杂的效果(如:经由历程转变元素位置完成动画)。但现实并不是如此,因为没有范例和范例,两种浏览器对雷同功用的完成确完全不一样。为了坚持顺序的兼容性,顺序员必需写一些探查代码以检测JavaScript是运转于哪一种浏览器之下,并供应与之对应的剧本。JavaScript陷入了亘古未有的杂沓,DHTML也因此在人们心中留下了很差的印象。
我们在浏览DOM范例的时刻,常常会看到DOM0级如许的字眼,实际上DOM0级这个范例是不存在的。所谓DOM0级只是DOM
汗青坐标系中的一个参照点罢了,详细地说DOM0级就是指IE4.0和Netscape navigator4.0最初支撑的谁人DHTML。
3.3、DOM1的涌现
在浏览器厂商举行浏览器大站的同时,W3C连系人人的长处推出了一个范例化的DOM,并于1998年10月完成了第一级 DOM,即:DOM1。W3C将DOM定义为一个与平台和编程言语无关的接口,经由历程这个接口顺序和剧本可以动态的接见和修正文档的内容、组织和款式。
DOM1级主要定义了HTML和XML文档的底层组织。在DOM1中,DOM由两个模块组成:DOM Core(DOM中心)和DOM HTML。个中,DOM Core划定了基于XML的文档组织范例,经由历程这个范例简化了对文档中恣意部份的接见和操纵。DOM HTML则在DOM中心的基础上加以扩大,增加了针对HTML的对象和要领,如:JavaScript中的Document对象.
3.4、DOM2
在DOM1的基础上DOM2引入了更多的交互才,也支撑了更高等的XML特征。DOM2将DOM分为更多具有联络的模块。DOM2级在本来DOM的基础上又扩大了鼠标、用户界面事宜、局限、遍历等细分模块,而且经由历程对象接口增添了对CSS的支撑。DOM1级中的DOM中心模块也经由扩大最早支撑XML定名空间。在DOM2中引入了以下模块,在模块包括了浩瀚新范例和新接口:
DOM视图(DOM Views):定义了跟踪差别文档视图的接口
DOM事宜(DOM Events):定义了事宜和事宜处置惩罚的接口
DOM款式(DOM Style):定义了基于CSS为元素运用款式的接口
DOM遍历和局限(DOM Traversal and Range):定义了遍历和操纵文档树的接口
完全的DOM2范例(图片来自百度百科):
3.5、DOM3
DOM3级:进一步扩大了DOM,引入了以一致体式格局加载和保留文档的要领,它在DOM Load And Save这个模块中定义;同时新增了考证文档的要领,是在DOM Validation这个模块中定义的。
DOM3进一步扩大了DOM,在DOM3中引入了以下模块:
DOM加载和保留模块(DOM Load and Save):引入了以一致体式格局加载和保留文档的要领
DOM考证模块(DOM Validation):定义了考证文档的要领
DOM中心的扩大(DOM Style):支撑XML 1.0范例,触及XML Infoset、XPath和XML Base
4、熟悉DOM
DOM可以将任何HTML描绘成一个由多层节点组成的组织。节点分为12种差别范例,每种范例离别示意文档中差别的信息及标记。每一个节点都具有各自的特性、数据和要领,也与其他节点存在某种关联。节点之间的关联组成了条理,而一切页面标记则表现为一个以特定节点为根节点的树形组织。
先看一张w3school上面的一张图:
先来看看下面代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>DOM</title>
</head>
<body>
<h2><a href="http://www.baidu.com">javascript DOM</a></h2>
<p>对HTML元素举行操纵,可增加、转变或移除css款式等</p>
<ul>
<li>Javascript</li>
<li>DOM</li>
<li>CSS</li>
</ul>
</body>
</html>
将HTML代码分解为DOM节点条理图:
HTML文档可以说由节点组成的鸠合,DOM节点有:
元素节点:上图中<html>、<body>、<p>等都是元素节点,即标签。
文本节点:向用户展现的内容,如<li>…</li>中的JavaScript、DOM、CSS等文本。
属性节点:元素属性,如<a>标签的链接属性href=”http://www.baidu.com”。
5、文档范例生长史
我们说DOM文档对象模子是从文档中笼统出来的,DOM操纵的对象也是文档,因此我们有必要相识一下文档的范例。文档跟着汗青的生长演变为多种范例,以下:
5.1、GML
GML(Generalized Markup Language, 通用标记言语)是1960年代的一种IBM文档花样化言语,用于形貌文档的组织组织、各部件及其互相关联。GML在文档详细花样方面,为文档员供应了一些随意马虎,他们没必要再为IBM的打印机花样化言语SCRIPT要求的字体范例、行距以及页面设想等糟蹋精神。这个IBM的GML包括1960年代的GML和1980年代的ISIL。
5.2、SGML
SGML(Standard Generalized Markup Language, 范例通用标记言语)是1986年基于IBM的GML制订ISO范例(ISO 8879)。SGML是现时常常运用的超文本花样的最高条理范例,是可以定义标记言语的元言语,以至可以定义没必要采纳”<>”的通例体式格局。因为SGML的庞杂,因此难以提高。HTML和XML一样衍生于SGML,XML可以被以为是SGML的一个子集,而HTML是SGML的一个运用。
5.3、HTML
HTML(HyperText Markup Language, 超文本标记言语)是为“网页建立和别的可在网页浏览器中看到的信息”设想的一种标记言语。HTML被用来组织化信息——比方题目、段落和列表等等,也可用来在一定程度上形貌文档的表面和语义。1982年,蒂姆·伯纳斯-李为使世界各地的物理学家可以随意马虎的举行协作研讨,建立了运用于其体系的HTML。今后HTML又不停地扩大和生长,成为国际范例,由万维网同盟(W3C)保护。第一个正式范例是1995年宣布的RFC 1866(HTML 2.0)。
5.4、XML
XML(eXtensible Markup Language, 可扩大标记言语)是专家们运用SGML精简制造,并遵照HTML的生长履历,发生出一套运用上划定规矩严谨,然则简朴的形貌数据言语。XML在1995年最早有雏形,在1998二月宣布为W3C的范例(XML1.0)
5.5、XHTML
XHTML(eXtensible HyperText Markup Language, 可扩大超文本标记言语)的表现体式格局与超文本标记言语(HTML)相似,不过语法上越发严厉。从继续关联上讲,HTML是一种基于范例通用标记言语(SGML)的运用,是一种异常天真的置标言语,而XHTML则基于可扩大标记言语(XML),XML是SGML的一个子集。XHTML 1.0在2000年1月26日成为W3C的引荐范例。
6、DOM节点范例
DOM1级定义了一个Node接口,这个Node接口在javascript中是作为Node范例来完成的。除了IE以外,其他一切浏览器都可以接见这个范例。每一个节点都有一个nodeType属性,用于表明节点的范例。节点范例经由历程定义数值常量和字符常量两种体式格局来示意,IE只支撑数值常量。节点范例一共有12种,这里引见常常运用的7种范例。以下图:
看下面这个例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DocumentFragment文档片断节点</title>
</head>
<body>
<!-- tip地区 -->
<div id="tip">test1</div>
<ul class="list-node">
<li>test2<li>
</ul>
<script>
var frag = document.createDocumentFragment();
for (var i = 0; i < 10; i++) {
var li = document.createElement("li");
li.innerHTML = "List item" + i;
frag.appendChild(li);
}
document.getElementById("list-node").appendChild(frag);
</script>
</body>
</html>
以下援用均来自先生说的话,觉得每句话都很主要,所以就写下来了。
(1)Element(元素节点):
是组成文档树的主要部份,它示意了html、xml文档中的元素。平常元素因为有子元素、文本节点或许两者的连系,元素节点是唯一可以具有属性的节点范例。
例子中的:html
、heade
、meta
、title
、body
、div
、ul
、li
、script
都属于Element(元素节点);
(2)Attr(属性节点):
代表了元素中的属性,因为属性实际上是附属于元素的,因此属性节点不能被看作是元素的子节点。因此在DOM中属性没有被以为是文档树的一部份。换句话说,属性节点实在被看作是包括它的元素节点的一部份,它并不作为零丁的一个节点在文档树中涌现。
例子中的:lang
、charset
、id
、class
都属于Attr(属性节点);
(3)Text(文本节点):
是只包括文本内容的节点,在xml中称为字符数据,它可以由更多的信息组成,也可以只包括空缺。在文档树中元素的文本内容和属性的文本内容都是由文本节点来示意的。
例子中的:DocumentFragment文档片断节点
、test1
、test2
、元素节点今后的空缺地区
都属于Text(文本节点);
(4)Comment(诠释节点):
示意诠释的内容
例子中的:<!-- tip地区 -->
都属于Comment(诠释节点);
(5)Document(文档节点) :
是文档树的根节点,它是文档中其他一切节点的父节点。要注重的是,文档节点并不是html、xml文档的根元素,因为在xml文档中,处置惩罚指令、诠释等内容可以出如今根元素以外,所以我们在组织DOM树的时刻,根元素并不适协作为根节点,因此就有了文档节点,而根元素是作为文档节点的子节点涌现的。
例子中的:<!DOCTYPE html>
、html
作为Document(文档节点)的子节点涌现;
(6)DocumentType(文档范例节点):
每一个Document都有一个DocumentType属性,它的值或许是null,或许是DocumentType对象。比方声明文档范例时<!doctype html>就是文档范例节点。
例子中的:<!DOCTYPE html>
就属于DocumentType(文档范例节点);
(7)DocumentFragment(文档片断节点):
是轻量级的或最小的Document对象,它示意文档的一部份或许是一段,不属于文档树。不过它有一种特别的行动,该行动使得它异常有效。比方:当要求把一个DocumentFragment节点插进去到文档的时刻,插进去的不是DocumentFragment本身,而是它的一切的子孙节点。这使得DocumentFragment成了有效的占位符,临时寄存那些一次插进去文档的节点,同时它另有利于完成文档的剪切、复制和粘贴等操纵。
例子中的:var frag = document.createDocumentFragment();
就属于DocumentFragment(文档片断节点);
7、DOM的nodeType、nodeName、nodeValue
7.1 nodeType
经由历程DOM节点范例,我们可知,可以经由历程某个节点的nodeType属性来取得节点的范例,节点的范例可所以数值常量或许字符常量。示例代码以下:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>nodeType</title>
</head>
<body>
<div id="container">这是一个元素节点</div>
<script>
var divNode = document.getElementById('container');
/*
IE中只支撑数值常量,因为低版本IE浏览器没有内置Node对象,其他浏览器数值常量和字符常量都支撑,因此可
以直接用数值常量推断,这里为了比较两种写法,便都写在了这里
*/
if (divNode.nodeType == Node.ELEMENT_NODE || divNode.nodeType === 1) {
alert("Node is an element.");
}
</script>
</body>
</html>
7.2 nodeName和nodeValue
先看示例代码:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>nodeName,nodeValue</title>
</head>
<body>
<!--nodeName,nodeValue试验-->
<div id="container">这是一个元素节点</div>
<script>
var divNode = document.getElementById('container');
console.log(divNode.nodeName + "/" + divNode.nodeValue);
//效果: DIV/null
var attrNode = divNode.attributes[0];
console.log(attrNode.nodeName + "/" + attrNode.nodeValue);
//效果: id/container
var textNode = divNode.childNodes[0];
console.log(textNode.nodeName + "/" + textNode.nodeValue);
//效果: #text/这是一个元素节点
var commentNode = document.body.childNodes[1];
//示意取第二个诠释节点,因为body下面的第一个诠释节点为空缺符。
console.log(commentNode.nodeName + "/" +commentNode.nodeValue);
//效果: #comment/nodeName,nodeValue试验
console.log(document.doctype.nodeName + "/" + document.doctype.nodeValue);
//效果: html/null
var frag = document.createDocumentFragment();
console.log(frag.nodeName + "/" + frag.nodeValue);
//效果: #document-fragment/null
</script>
</body>
</html>
依据试验,得出以下汇总表格:
8、domReady
还记得刚最早进修JavaScript时刻,常常会犯如许的毛病:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Dom not ready</title>
<script>
document.getElementById("header").style.color = "red";
</script>
</head>
<body>
<h1 id="header">这里是h1元素包括的内容</h1>
</body>
</html>
末了发明效果并不是我们想要的,笔墨并没有变成赤色,我想最早入门进修JavaScript操纵DOM时刻多若干少会碰到这类疑心和毛病,实在涌现这类题目的缘由就是我们没有辨别HTML标签和DOM节点的辨别的原因了,由这个题目就引出下面要说的domReady和浏览器衬着剖析道理了。
8.1、什么是domReady?
html是一种标记言语,它通知我们这个页面有什么内容,但行动交互是须要经由历程DOM操纵来完成的。我们不要以为有两个尖括号就以为它是一个DOM了,html标签要经由历程浏览器剖析才会变成DOM节点,当我们向地点栏传入一个url的时刻,我们最早加载页面,就可以看到内容,在这时期就有一个DOM节点构建的历程。节点是以树的情势组织的,当页面上一切的html都转换为节点今后,就叫做DOM树构建终了,简称为domReady。
8.2、那末浏览器是怎样将html标签剖析变成DOM节点的呢?
实际上浏览器是经由历程衬着引擎来完成的。衬着引擎的职责就是把要求的内容显现到浏览器屏幕上。默许状况下衬着引擎可以显现html、xml文档及图片。经由历程插件(浏览器扩大)它可以显现其他范例的文档,比方我们装置pdf viewer插件,我们就可以显现pdf文档。这里专注衬着引擎的主要用途,等于将css花样化的html和图片在浏览器上举行显现。
8.3、浏览器衬着引擎的基础衬着流程
浏览器衬着要做的事就是把CSS,HTML,图片等静态资本展现到用户面前。
衬着引擎起首经由历程收集取得所要求文档的内容,平常以8k分块的要领来完成:
上图就是html衬着的基础历程,但这并不包括剖析历程当中浏览器加载外部资本,比方图片、剧本、iframe等的一些历程。说白了,上面的4步仅仅是html组织的衬着历程。而外部资本的加载在html组织的衬着历程当中是坚持到底的,纵然绘制DOM节点已完成,而外部资本依然能够正在加载或许还没有加载。
8.4、Webkit主要衬着流程
Firefox浏览器Gecko衬着流程跟Webkit内核衬着相似,迥然差别,WebKit 和 Gecko 运用的术语略有差别,但团体流程是基础雷同的。这里以Webkit内核作为例子来申明浏览器衬着的主要流程。
浏览器的衬着道理并不是一言半语,几个图就可以说邃晓的,上图说的只是引见一个大环节的历程和步骤,这里举一反三象征性说个也许,更多关于浏览器内部事情道理的文章,请浏览:浏览器的事情道理:新式收集浏览器幕后揭秘
8.5、domReady的完成战略
上面的各个代码实例中,并没有斟酌domReady,顺序也能平常运转,因为我们把javascript代码写在了body元素末了的位置。因为浏览器是从上到下,从左向右衬着元素的,如许实例中的js代码一定在domReady今后去实行的。那为何还要用domReady呢?现实上,我们在编写大型项目的时刻,js文件每每异常多,而且之间会互相挪用,大多数都是外部援用的,不把js代码直接写在页面上。如许的话,假如有个domReady这个要领,我们想用它就挪用,不论逻辑代码写在那里,都是比及domReady今后去实行的。
window.onload要领,示意当页面一切的元素都加载终了,而且一切要要求的资本也加载终了才触发实行function这个匿名函数里边的详细内容。如许一定保证了代码在domReady今后实行。运用window.onload要领在文档外部资本不多的状况下不会有什么题目,然则当页面中有大批长途图片或要要求的长途资本时,我们须要让js在点击每张图片时,举行响应的操纵,假如此时外部资本还没有加载终了,点击图片是不会有任何回响反映的,大大降低了用户体验。那既然window.onload要领不可行,又该怎样做呢?
你一定想到了jquery中的$(document).ready(function(){})要领了,实在jquery中的domReady应当和window.onload的完成道理是迥然差别的。为相识决window.onload的短板,w3c 新增了一个 DOMContentLoaded 事宜。
这里提到了DOMContentLoaded事宜,这里因为篇幅有限,就不多做引见,这内里也有很多细节可以进修,有兴致的童鞋,可以看看我之前珍藏的两篇文章:
你不晓得的 DOMContentLoaded&version=12020110&nettype=WIFI&fontScale=100&pass_ticket=2uOqWTPNenLxF7wD%2F%2Bi%2F0TK60XMDQLdZ%2Bk2hyDjtKZsM9jitnQM4c%2B5cVfq0SJLP)
浅谈DOMContentLoaded事宜及其封装要领
进修就是一个无底洞,因为深不可测,才让人不停探究。
参考jquery中domReady的完成道理,来看一下javascript中domReady的完成战略。
在页面的DOM树建立完成后(也就是HTML剖析第一步完成)即触发,而无需守候其他资本的加载。即domReady完成战略:
1. 支撑DOMContentLoaded事宜的,就运用DOMContentLoaded事宜。
2. 不支撑的就用来自Diego Perini发明的有名Hack兼容。兼容道理也许就是经由历程IE中的document,
documentElement.doScroll('left')来推断DOM树是不是建立终了。
JavaScript完成domReady,【domReady.js】
function myReady(fn){
//关于当代浏览器,对DOMContentLoaded事宜的处置惩罚采纳范例的事宜绑定体式格局
if ( document.addEventListener ) {
document.addEventListener("DOMContentLoaded", fn, false);
} else {
IEContentLoaded(fn);
}
//IE模仿DOMContentLoaded
function IEContentLoaded (fn) {
var d = window.document;
var done = false;
//只实行一次用户的回调函数init()
var init = function () {
if (!done) {
done = true;
fn();
}
};
(function () {
try {
// DOM树未建立完之前挪用doScroll会抛出毛病
d.documentElement.doScroll('left');
} catch (e) {
//耽误再试一次~
setTimeout(arguments.callee, 50);
return;
}
// 没有毛病就示意DOM树建立终了,然后立马实行用户回调
init();
})();
//监听document的加载状况
d.onreadystatechange = function() {
// 假如用户是在domReady今后绑定的函数,就立马实行
if (d.readyState == 'complete') {
d.onreadystatechange = null;
init();
}
}
}
}
在页面中引入donReady.js文件,援用myReady(回调函数)要领即可。
感兴致的童鞋可以看看各个主流框架domReady的完成:点击我检察
8.6、一个小栗子看两者差异性
下面经由历程一个案例,来比较domReady与window.onload完成的差别,很显著,onload事宜是要在一切要求都完成今后才实行,而domReady运用hack手艺,在加载完dom树今后就可以实行,所以domReady比onload实行时候更早,发起采纳domReady。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>domReady与window.onload</title>
<script src="domReady.js"></script>
</head>
<body>
<div id="showMsg"></div>
<div>
<img src="http://ww1.sinaimg.cn/large/ae49ba57gy1fe9zofelhdj20xc0xc42s.jpg" alt="">
<img src="http://ww1.sinaimg.cn/large/ae49ba57gy1fe9zofahw3j20m80etq4a.jpg" alt="">
<img src="http://ww1.sinaimg.cn/large/ae49ba57gy1fe9zoi3ny6j20l20dw4gd.jpg" alt="">
<img src="http://ww1.sinaimg.cn/large/ae49ba57gy1fe9zog3tauj20m80et0uw.jpg" alt="">
<img src="http://ww1.sinaimg.cn/large/ae49ba57gy1fe9zofi2o5j20m80ettaq.jpg" alt="">
<img src="http://ww1.sinaimg.cn/large/ae49ba57gy1fe9zohjuvhj20tb0cdwvp.jpg" alt="">
</div>
<script>
var d = document;
var msgBox = d.getElementById("showMsg");
var imgs = d.getElementsByTagName("img");
var time1 = null,
time2 = null;
myReady(function() {
msgBox.innerHTML += "dom已加载!<br>";
time1 = new Date().getTime();
msgBox.innerHTML += "时候戳:" + time1 + "<br>";
});
window.onload = function() {
msgBox.innerHTML += "onload已加载!<br>";
time2 = new Date().getTime();
msgBox.innerHTML += "时候戳:" + time2 + "<br>";
msgBox.innerHTML += "domReady比onload快:" + (time2 - time1) + "ms<br>";
};
</script>
</body>
</html>
实行效果对照,发明DomReady比onload快活2秒多。
9、元素节点的推断
为何要推断元素的节点?
因为要推断元素节点范例,因为属性的一系列操纵与元素的节点范例息息相干,假如我们不辨别它们,我们就不晓得用元素的直接属性操纵(比方:ele.xxx=yyy)照样用一个要领操纵(el.setAttribute(xxx,yyy))。
设想元素范例的剖断,这里给出有4个要领:
(1). isElement :剖断某个节点是不是为元素节点
(2). isHTML :剖断某个节点是不是为html文档的元素节点
(3). isXML : 剖断某个节点是不是为xml文档的元素节点
(4). contains :用来剖断两个节点的包括关联
9.1、元素节点的剖断:isElement
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>isElement</title>
</head>
<body>
<div id="test">aaa</div>
<!--这是一个诠释节点-->
<script>
var isElement = function (el){
return !!el && el.nodeType === 1;
}
var a = { //随意定义一个变量,设置nodeType为1
nodeType: 1
}
console.log(isElement(document.getElementById("test")));
//效果: true
console.log(isElement(document.getElementById("test").nextSibling));
//这里的nextSibling属性查找下一个相邻节点,即诠释节点
//效果: false
console.log(isElement(a));
//效果: true
</script>
</body>
</html>
注重代码中的!!用法:!!平常用来将背面的表达式转换为布尔型的数据(boolean).
因为javascript是弱范例的言语(变量没有牢固的数据范例)所以偶然须要强迫转换为响应的范例,关于JavaScript的隐式转换,可以看看之前我写的一篇博客,这篇文章险些剖析到了一切的转换划定规矩,感兴致的童鞋可以点击查阅,进修相识一下。
[从++[[]][+[]]+[+[]]==10?深切浅出弱范例JS的隐式转换](https://github.com/jawil/blog…
注重:上面的代码定义了一个变量a,将它的nodeType的值设为1,因为元素节点的节点范例的数值常量为1,所以这里在打印的的时刻,会将a以为是元素节点,所以打印true。这类效果显著不是我们想要的,纵然这类状况很少涌现。下面给出处理计划:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>isElement</title>
</head>
<body>
<div id="test">aaa</div>
<!--这是一个诠释节点-->
<script>
var testDiv = document.createElement('div');
var isElement = function (obj) {
if (obj && obj.nodeType === 1) {//先过滤最简朴的
if( window.Node && (obj instanceof Node )){
//假如是IE9,则剖断其是不是Node的实例
return true; //因为obj多是来自另一个文档对象,因此不能随意马虎返回false
}
try {//末了以这类效力异常差但一定可行的计划举行剖断
testDiv.appendChild(obj);
testDiv.removeChild(obj);
} catch (e) {
return false;
}
return true;
}
return false;
}
var a = {
nodeType: 1
}
console.log(isElement(document.getElementById("test")));
//效果: true
console.log(isElement(document.getElementById("test").nextSibling));
//效果: false
console.log(isElement(a));
//效果: false
</script>
</body>
</html>
如许,在推断a是不是是元素节点时,效果就是false了。
更多关于元素节点的推断请参考:How do you check if a JavaScript Object is a DOM Object?
9.2、HTML文档元素节点的剖断和XML文档元素节点的剖断:isHTML and isXML
我们可以简朴的将一切的元素节点化为两类:一类是HTML,一类是XML。不过从严厉意义上来说,HTML只是XML的一个子集,它具有更多的特征,而XML在矢量画图的处置惩罚上又派生出了两大类:SVG和VML。那末根据这类要领,我们可以简朴的以为假如不是HTML,就是XML的元素节点了。而HTML是比较随意马虎辨认的,因为它有更多的特征。比方说,XML是没有className的,或许我们经由历程一个元素的ownerDocument获得它的文档对象,XML是没有document.getElementById()和document.getElementsByTagName()这些要领的.另外,最大的辨别是HTML元素的nodeName老是大写的,当你运用createElement()要领建立HTML元素的时刻,不管你传入的字母是大写照样小写,末了获得的都是大写。
接下来就看看各大类库是怎样完成HTML和XML文档的元素节点的剖断的。
9.2.1、Sizzle, jQuery自带的选择器引擎,推断是不是是XML文档
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>isXML</title>
</head>
<body>
<script>
//Sizzle, jQuery自带的选择器引擎
var isXML = function(elem) {
var documentElement = elem && (elem.ownerDocument || elem).documentElement;
return documentElement ? documentElement.nodeName !== "HTML" : false;
};
console.log(isXML(document.getElementById("test")));
//但如许不严谨,因为XML的根节点,也多是HTML标签,比方如许建立一个XML文档
try {
var doc = document.implementation.createDocument(null, 'HTML', null);
console.log(doc.documentElement);
console.log(isXML(doc));
} catch (e) {
console.log("不支撑creatDocument要领");
}
</script>
</body>
</html>
浏览器随意找个HTML页面考证一下:
9.2.1、mootools的slick选择器引擎的源码,推断是不是是XML文档
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>isXML</title>
</head>
<body>
<script>
//我们看看mootools的slick选择器引擎的源码:
var isXML = function(document) {
return (!!document.xmlVersion) || (!!document.xml) || (toString.call(document) == '[object XMLDocument]')
|| (document.nodeType == 9 && document.documentElement.nodeName != 'HTML');
};
//精简版
var isXML = window.HTMLDocument ? function(doc) {
return !(doc instanceof HTMLDocument);
} : function(doc) {
return "selectNodes" in doc;
}
</script>
</body>
</html>
不过,这些要领都只是范例,javascript对象是可以随意增加的,属性法很随意马虎被攻破,最好是运用功用法。功用法的完成代码以下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>isXML</title>
</head>
<body>
<script>
var isXML = function(doc) {
return doc.createElement("p").nodeName !== doc.createElement("P").nodeName;
}
</script>
</body>
</html>
我们晓得,不管是HTML文档,照样XML文档都支撑createELement()要领,我们剖断建立的元素的nodeName是辨别大小写的照样不辨别大小写的,我们就晓得是XML照样HTML文档,这个要领是现在给出的最严谨的函数了。
推断是不是是HTML文档的要领以下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>isHTML</title>
</head>
<body>
<script>
var isHTML = function(doc) {
return doc.createElement("p").nodeName === doc.createElement("P").nodeName;
}
console.log(isHTML(document));
</script>
</body>
</html>
有了以上推断XML和HTML文档的要领,我们就可以完成一个元素节点属于HTML照样XML文档的要领了,完成代码以下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>isHTMLElement</title>
</head>
<body>
<script>
var testDiv = document.createElement('div');
var isElement = function (obj) {
if (obj && obj.nodeType === 1) {//先过滤最简朴的
if( window.Node && (obj instanceof Node )){
//假如是IE9,则剖断其是不是Node的实例
return true; //因为obj多是来自另一个文档对象,因此不能随意马虎返回false
}
try {//末了以这类效力异常差但一定可行的计划举行剖断
testDiv.appendChild(obj);
testDiv.removeChild(obj);
} catch (e) {
return false;
}
return true;
}
return false;
}
var isHTML = function(doc) {
return doc.createElement("p").nodeName === doc.createElement("P").nodeName;
}
var isHTMLElement = function(el){
if(isElement){
return isHTML(el.ownerDocument);
}
return false;
}
console.log(isHTMLElement(testDiv));
</script>
</body>
</html>
9.3、推断节点的包括关联
DOM可以将任何HTML描绘成一个由多层节点组成的组织。节点分为12种差别范例,每种范例离别示意文档中差别的信息及标记。每一个节点都具有各自的特性、数据和要领,也与其他节点存在某种关联。节点之间的关联组成了条理,而一切页面标记则表现为一个以特定节点为根节点的树形组织。DOM间的节点关联大抵以下。
节点关联不仅仅指元素节点的关联,document文档节点也包括在内。在最新的浏览器中,一切的节点都已设备了contains()要领,
元素之间的包括关联,用自带的contains要领,只要两个都是元素节点,才兼容各个浏览器,不然ie浏览器有的版本是不支撑的,可以采纳hack手艺,本身写一个contains要领去兼容。
元素之间的包括关联:contains()要领.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>contains</title>
</head>
<body>
<div id="p-node">
<div id="c-node">子节点内容</div>
</div>
<script>
var pNode = document.getElementById("p-node");
var cNode = document.getElementById("c-node").childNodes[0];
alert(pNode.contains(cNode)); //true
</script>
</body>
</html>
兼容各浏览器的contains()要领
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>contains</title>
</head>
<body>
<div id="p-node">
<div id="c-node">子节点内容</div>
</div>
<script>
//兼容的contains要领
function fixContains(a, b) {
try {
while ((b = b.parentNode)){
if (b === a){
return true;
}
}
return false;
} catch (e) {
return false;
}
}
var pNode = document.getElementById("p-node");
var cNode = document.getElementById("c-node").childNodes[0];
alert(fixContains(pNode, cNode)); //true
alert(fixContains(document, cNode)); //true
</script>
</body>
</html>
10、DOM节点继续条理与嵌套划定规矩
10.1、DOM节点继续条理
DOM节点是一个异常庞杂的东西,对它的每一个属性的接见,不交运的话,就能够会向上溯寻到N多个原型链,因此DOM操纵是个异常耗机能的操纵。风头正盛的react为相识决这个题目,提出了假造DOM的观点,合并和屏障了很多无效的DOM操纵,效果异常惊人。接下来看看DOM节点终究是怎样继续的。
10.1.1、建立一个元素节点(Element)的历程
运用document.createElement(“p”)建立p元素,实在document.createElement(“p”)是HTMLParagraphElement的一个实例,而HTMLParagraphElement的父类是HTMLElement,HTMLElement的父类是Element,Element的父类是Node,Node的父类是EventTarget,EventTarget的父类是Function,Function的父类是Object。
建立一个p元素一共溯寻了7层原型链:
下面我们来剖析一下建立一个元素所继续的属性离别是啥。
1.document.createElement(“p”)
document.createElement(“p”)起首就是一个实例对象,它是由组织函数HTMLParagraphElement发生的,你可以这么看这个题目:
function HTMLParagraphElement() {
[native code]
}
document.createElement("p")=new HTMLParagraphElement('p');
由以上继续关联可以看出来:
`document.createElement(“p”).constructor===HTMLParagraphElement
document.createElement(“p”).__proto__===HTMLParagraphElement.prototype
`
对实例对象,组织函数,以及JavaScript原型链和继续不太熟习的童鞋,该补习一下基础看看了。
我们先来看看document.createElement(“p”)本身有哪些属性,遍历对象属性要领平常有三种:
先来说一讲遍历对象属性三种要领的差异性,当作补充温习。
遍历数组属性现在我晓得的有:for-in
轮回、Object.keys()
和Object.getOwnPropertyNames()
,那末三种到底有啥辨别呢?
for-in轮回:会遍历对象本身的属性,以及原型属性,包括enumerable 为 false(不可罗列属性);
Object.keys():可以获得本身可罗列的属性,但得不到原型链上的属性;
Object.getOwnPropertyNames():可以获得本身一切的属性(包括不可罗列),但得不到原型链上的属性,Symbols属性
也得不到.
Object.defineProperty
望文生义,就是用来定义对象属性的,vue.js
的双向数据绑定主要在getter
和setter
函数内里插进去一些处置惩罚要领,当对象被读写的时刻处置惩罚要领就会被实行了。 关于这些要领和属性的更详细诠释,可以看MDN上的诠释(戳我);
简朴看一个小demo例子加深邃晓,关于Object.defineProperty
属性不太邃晓,可以看看上面引见的文档进修补充一下.
'use strict';
class A {
constructor() {
this.name = 'jawil';
}
getName() {}
}
class B extends A {
constructor() {
super();
this.age = 22;
}
//getAge不可罗列
getAge() {}
[Symbol('fullName')]() {
}
}
B.prototype.get = function() {
}
var b = new B();
//设置b对象的info属性的enumerable: false,让其不能罗列.
Object.defineProperty(b, 'info', {
value: 7,
writable: true,
configurable: true,
enumerable: false
});
//Object可以获得本身可罗列的属性,但得不到原型链上的属性
console.log(Object.keys(b)); //[ 'name', 'age' ]
//Object可A以获得本身一切的属性(包括不可罗列),但得不到原型链上的属性,Symbols属性也得不到
console.log(Object.getOwnPropertyNames(b)); //[ 'name', 'age', 'info' ]
for (var attr in b) {
console.log(attr);//name,age,get
}
//in会遍历对象本身的属性,以及原型属性
console.log('getName' in b); //true
有了上面的学问作为扩大,我们就可以清楚清楚明了的晓得,建立元素P标签每一步都继续了哪些属性,继续对象本身有哪些属性,因为篇幅有限,人人可以自行子在浏览器测试,看看这些对象的一些属性和要领,便于我们邃晓。
比方我们想看:HTMLElement对象有哪些本身属性,我们可以这么检察:
Object.getOwnPropertyNames(HTMLElement)
我们想看:HTMLElement的原型对象有哪些本身属性,我们可以这么检察:
Object.getOwnPropertyNames(HTMLElement.prototype)
HTMLElement的原型对象有哪些本身属性,依据原型链,我们也可以这么检察:
因为:document.createElement("p").__proto__.__proto__===HTMLElement.prototype
Object.getOwnPropertyNames(document.createElement("p").__proto__.__proto__)
10.1.2、建立一个文本节点(Text)的历程
运用document.createTextNode(“xxx”)建立文本节点,实在document.createTextNode(“xxx”)是Text的一个实例,而Text的父类是CharactorData,CharactorData的父类是Node,Node的父类是EventTarget,EventTarget的父类是Function,Function的父类是Object。
建立一个文本节点一共溯寻了6层原型链。
因此,一切节点的继续条理都不简朴,但相比较而言,元素节点是更恐怖的。从HTML1升级到HTML3.2,再升级到HTML4.1,再到HTML5,除了不停地增添新范例、新的嵌套划定规矩以外,每一个元素也不停的增加新属性。
下面看一个例子:建立一个p元素,打印它第一层原型的固有的属性的名字,经由历程Object的getOwnPropertyNames()猎取当前元素的一些属性,这些属性都是他的原始属性,不包括用户自定义的属性。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>DOM inheritance hierarchy</title>
</head>
<body>
<script>
console.log(Object.getOwnPropertyNames(document.createElement("p").__proto__));
//接见p元素上一层原型控制台打印: ["align","constructor"]
console.log(
Object.getOwnPropertyNames(document.createElement("p").__proto__.__proto__)
);
/*接见p元素上一层原型的再上一层原型,控制台会打印很多属性,感兴致的同伴可以本身贴代码到控制台看
一下,它要比访*问第一层原型的属性多得多。这也就是说,每往上一层,原型链就为它增加一些属性。
*/
</script>
</body>
</html>
10.1.3、空的div元素的自有属性
下面看一个空的div元素,而且没有插进去到DOM里边,看它有若干自有属性(不包括原型链继续来的属性)
在新的HTML范例中,很多元素的固有属性(比方value)都放到了原型链当中,数目就越发巨大了。因此,将来的生长方向是只管运用现成的框架来完成,比方MVVM框架,将一切的DOM操纵都转交给框架内部做邃密处置惩罚,这些完成计划固然就包括了假造DOM的手艺了。然则在运用MVVM框架之前,控制底层学问是异常主要的,邃晓为何如许做,为何不如许做的目的。这也是为何要邃晓DOM节点继续条理的目的。
10.2、HTML嵌套划定规矩
HTML存在很多种范例的标签,有的标签下面只许可特定的标签存在,这就叫HTML嵌套划定规矩。
不按HTML嵌套划定规矩写,浏览器就不会准确剖析,会将不符合嵌套划定规矩的节点放到目的节点的下面,或许变成纯文本。
关于HTML嵌套划定规矩,一定要控制块状元素和内联元素的辨别。
块状元素:平常是其他元素的容器,可包容内联元素和其他块状元素,块状元素排挤其他元素与其位于统一行,宽度(width)高度(height)起作用。罕见块状元素为div和p
内联元素:内联元素只能包容文本或许其他内联元素,它许可其他内联元素与其位于统一行,但宽度(width)高度(height)不起作用。罕见内联元素为a.
块状元素与内联元素嵌套划定规矩:
(1).块元素可以包括内联元素或某些块元素,但内联元素却不能包括块元素,它只能包括其他的内联元素
例:
<div><h1></h1><p></p></div>
<a href="#"><span></span></a>
(2).块级元素不能放在<p>内里
例:<p><ol><li></li></ol></p><p><div></div></p>
(3).有几个特别的块级元素首倡只能包括内联元素,不能再包括块级元素,这几个特别的标签是:
h1、h2、 h3、h4、 h5、 h6、 p 、dt
(4).li标签可以包括div标签
例:
<li><div></div></li>
(5).块级元素与块级元素并列,内联元素与内联元素并列
例:
<div><h2></h2><p></p></div>
<div><a href="#"></a><span></span></div>