DOM
(文档对象模型)是针对HTML和XML文档的一个API(应用程序编程接口)。DOM描绘了一个层次化的节点树,容许开发人员添加、移除和修改页面的某一部分。DOM
脱胎于Netscape及微软公司创始的DHTML(动态HTML),但如今它已经成为表现和操做页面标记的真正跨平台、语言中立方式。COM
对象的形式实现的。这意味着IE中的DOM
对象与原生JavaScript对象的行为或活动特色并不一致。本章将较多的谈及这些差别。<html> <head> <title>Sample Page</title> </head> <body> <p>Hello World!</p> </body> </html>
<html>
元素,咱们称之为文档元素。<html>
元素。在XML中,没有预约义的元素,所以任何元素均可能成为文档元素。Node
接口,该接口将由 DOM 中全部节点类型实现。这个Node接口在JavaScript中是做为Node
类型实现的;除了IE以外,在其余全部浏览器中均可以访问到这个类型。Node
类型,所以全部节点类型都共享着相同的基本属性和方法。每一个节点都有一个nodeType
属性,用于代表节点的类型。及诶单类型由在Node
类型中定义的下列12个数值常量来表示,任何节点类型必居其一(编号为节点类型常量存储的数值):javascript
Node.ELEMENT_NODE
Node.ATTRIBUTE_NODE
Node.TEXT_NODE
Node.CDATA_SECTION_NODE
Node.ENTITY_REFERENCE_NODE
Node.ENTITY_NODE
Node.PROCESSING_INSTRUCTION_NODE
Node.COMMENT_NODE
Node.DOCUMENT_NODE
Node.DOCUMENT_TYPE_NODE
Node.DOCUMENT_FRAGMENT_NODE
Node.NOTATION_NODE
// 经过比较上面的常量,很容易的肯定节点类型 // 在IE中无效 if (someNode.nodeType == Node.ELEMENT_NODE) { console.log("Node is an element"); } // 因为IE没有公开 Node 类型的构造函数 // 最好仍是将 nodeType 属性与数字比较 if (someNode.nodeType == 1) { console.log("Node is an element"); }
nodeName
和 nodeValue
属性nodeName
和 nodeValue
两个属性。这两个属性的值彻底取决于节点类型。在使用这两个值之前,最好用上述的代码检查节点的类型。if (someNode.nodeType == 1) { value = someNode.nodeName; // nodeName的值是元素的标签名 }
childNodes
属性,其中保存着一个NodeList
对象。注意,能够经过方括号语法来访问NodeList
的值,并且也有length
属性,但它并非Array
的实例。NodeList
对象的独特之处在于,它其实是基于DOM结构动态执行查询的结果,所以DOM结构的变化可以自动反映在NodeList
对象中。咱们常说NodeList
是有生命、有呼吸的对象,而不是咱们第一次访它的瞬间拍摄下来的一张快照。// 方括号和 item() 语法结果是相同的 var firstChild = someNode.childNodes[0]; var secondChild = someNode.childNodes.item(1); var count = comeNode.childNodes.length; // 虽然不是Array的实例,但咱们能够将它转换成数组 // 在IE8及以前的版本中无效 var arrayOfNodes = Array.prototype.slice.call(someNode.childNodes, 0);
// 因为IE8及更早版本将 NodeList 实现为一个 COM 对象 // 必须手动枚举全部成员,才能转换成数组 function convertToArray(nodes) { var array = null; try { array = Array.prototype.slice.call(nodes, 0); // 针对非IE浏览器 } catch (ex) { array = new Array(); for (var i=0, len=nodes.length; i < len; i++) { array.push(nodes[i]); } } return array; }
parentNode
属性,指向文档中的父节点。childNodes
中的全部节点都具备相同的父节点,而相互之间是同胞节点。previousSibling
和 nextSibling
属性能够访问同一列表中的其余节点。列表第一个节点previousSibling
为null
,列表最后一个nextSibling
为null
,固然若是列表只有一个节点,那么两个都是null
。firstChild
和lastChild
属性分别指向第一个和最后一个。若是列表没有节点,那么两个属性都是null
。hasChildNodes()
也是一个很是有用的方法,当查询节点存在子节点时返回true
,不存在返回false
。这是比查询childNodes.length
更简单的方法。ownerDocument
,该属性指向表示整个文档的文档节点。这种关系表示的是任何节点都属于它所在的文档,任何节点都不能同时存在两个或更多个文档中。经过这个属性,咱们能够没必要在节点层次中经过层层回溯达到顶端,而是能够直接访问文档节点。appendChild()
,用于向childNodes
列表的末尾添加一个节点,执行后,方法返回新增的节点。var returnedNode = someNode.appendChild(newNode); console.log(returnedNode == newNode); // true console.log(someNode.lastChild ==newNode); // true
childNodes
列表中某个特定的位置上,而不是放在末尾,可使用insertBefore()
方法。这个方法接收两个参数:要插入的节点和做为参照的节点。插入节点后,被插入的节点会变成参照节点的前一个同胞节点(previousSibling),同时被方法返回。若是参照节点是null
,则 insertBefore()
和 appendChild()
执行相同操做。// 插入后成为最后一个子节点 var returnedNode = someNode.insertBefore(newNode, null); // 插入后成为第一个子节点 var returnedNode = someNode.insertBefore(newNode, someNode.firstChild); // 插入后在最后一个子节点前面 var returnedNode = someNode.insertBefore(newNode, someNode.lastChild);
replaceChild()
替换节点。一样接收两个参数,插入的节点和参照节点。插入新的节点并将参照节点从文档树中移除,新的节点会从被替换的节点复制全部关系指针。尽管从技术上讲,被替换的节点仍然在文档中,但它在文档中的位置已经不存在了。removeChild()
移除节点。被移除的节点仍然在文档中,但它在文档中的位置已经不存在了。cloneNode()
用于建立调用这个方法的节点的一个彻底相同的副本。接收一个布尔值参数,表示是否执行深复制。css
appendChild()
insertBefore()
replaceChild()
将它添加到文档中。clone()
方法不会复制添加到DOM节点中的JavaScript属性,例如时间处理程序。这个方法只复制特性、(在明确指定的状况下也复制)子节点,其余一切都不会复制。<ul id="ul"> <li>item 1</li> <li>item 2</li> <li>item 3</li> </ul>
var myList = document.getElementById("ul"); var deepList = myList.cloneNode(true); // [text, li, text, li, text, li, text] console.log(deepList.childNodes); // 3 (IE < 9) 或 7 (其余浏览器) // IE8及以前的版本不会为包含空白符的文字建立节点(TEXT) console.log(deepList.childNodes.length); var shallowList = myList.cloneNode(false); console.log(shallowList.childNodes.length); // 0
normalize()
方法惟一的做用就是处理文档树中的文本节点。因为解析器的实现或DOM操做等缘由,可能会出现文本节点不包含文本,或者链接出现两个节点的状况。当在某个节点上调用这个方法时,就会在该节点的后代节点中查找上述两种状况。html
var html = document.documentElement; // 取得对<html>的引用 console.log(html == document.childNodes[0]); // true console.log(html == document.firstchild) // true
document.documentElement
和 document.boyd
属性<!DOCTYPE>
标签当作一个与文档其余部分不一样的实体,能够经过doctype属性(在浏览器中是document.doctype
)来访问信息。浏览器对document.doctype
的支持差异很大,因此这个属性的用途颇有限:java
document.doctype
的值始终为null
document.doctype
是一个DocumentType节点,也能够经过document.firstChild
或document.childNodes[0]
访问同一个节点。document.doctype
是一个DocumentType节点,但该节点不会出如今document.childNodes
中。<html>
元素外部的注释应该是算是文档的子节点。然而,不一样的浏览器在是否解析这些注释以及可否正确处理他们等方面,也存在很大差别。<!-- 第一条注释 --> <html> <body> </body> </html> <!-- 第二条注释 -->
看起来这个页面应该有3个子节点:注释、<html>
元素、注释。从逻辑上讲,咱们会认为document.childNodes
中应该包含与这3个节点对应的3项。可是实际上,浏览器存在如下差别:node
document.childNodes
中的第一个子节点。document
对象上调用appendChild()
removeChild()
replaceChild()
方法,由于文档类型(若是存在的话)是只读的,并且它只能有一个元素子节点(该节点一般早就已经存在了)。document
对象还有一些标准的Document对象所没有的属性。title
包含着<title>
元素中的文本。经过这个属性能够取得当前页面的标题,也能够修改当前页面的标题并反映在浏览器的标题栏中。修改title
属性的值会改变<title>
元素。// 取得文档标题 var originalTitle = document.title; // 设置文档标题 document.title = "New page title";
下面三个属性与网页的请求有关,全部这些信息都存在于请求的HTTP头部,只不过是经过这些属性让咱们可以在JavaScript中访问它们而已:编程
URL
属性中包含页面完整的URL(地址栏中的URL)domain
属性中值包含页面的域名referrer
属性中可能会包含空字符串URL
与domain
属性是相互关联的。例如document.URL
等于"http://www.wrox.com/WileyCDA/",那么document.domain
就等于"www.wrox.com"。domain
能够设置,但有安全方面的限制。若是URL中包含一个子域名,例如"p2p.wrox.com",那么就只能讲domain
设置为"wrox.com"(URL中包含"www",如"www.wrox.com"时,也是如此)。document.domain
就很是方便了。因为跨域安全限制,来自不一样子域的页面没法经过JavaScript通讯。而经过将每一个页面的document.domain
设置为相同的值,这些页面就能够互相访问对方包含的JavaScript对象了。// 取得完整的URL var url = document.URL; // 取得域名 var domain = document.domain; // 取得来源 页面的URL var referrer = document.referrer;
domain
属性还有一个限制,即若是域名一开始是“松散的”(loose),那么就不能将它再设置为“紧绷的”(tight)。// 假设页面来自于 p2p.wrox.com域 document.domain = "wrox.com"; // 松散的(成功) document.domain = "p2p.wrox.com"; // 紧绷的(出错)
getElementById()
接收一个参数:要取得的元素的ID。找到相应的元素则返回该元素,不然返回null
。跨域
<input type="text" name="myElement" value="Text field"> <div id="myElement">A div</div> <script> // IE7中调用会返回<input>元素 var el = document.getElementById("myElement"); </script>
getElementsByTagName()
接收一个参数:要取得的元素的标签名,而返回的是包含零或多个元素的NodeList
。可使用方括号语法或item()
方法来访问对象中的项。namedItem()
使用这个方法能够经过元素的name特性取得集合中的项。或方括号语法能达到一样的效果<img src="myimage.gif" name="myImage"> <script> var images = document.getElementsByTagName("img"); console.log(images.length); console.log(images[0].src); // 方括号传入数值就调用 item() console.log(images.item(0).scr); var myImage = images.namedItem("myImage"); var myImage = images["myImage"]; // 方括号传入字符串就调用namedItem() </script>
getElementsByTagName()
中传入"*"。在JavaScript及CSS中,星号一般表示所有。getElementsByTagName()
的标签名是不须要区分大小写的。但对于XML页面而言(包括XHTML),getElementsByTagName()
方法就会区分大小写。getElementByName()
是只有HTMLDocument类型才有的方法,返回带有给定name属性的全部元素。最常使用的状况是取得单选按钮;为了确保发送给浏览器的值正确无误,全部单选按钮必须具备相同的name特性<fieldset> <legend>Which color do you prefer?</legend> <ul> <li> <input type="radio" value="red" name="color" id="colorRed"> <label for="colorRed">Red</label> </li> <li> <input type="radio" value="green" name="color" id="colorGreen"> <label for="colorGreen">Green</label> </li> <li> <input type="radio" value="blue" name="color" id="colorBlue"> <label for="colorBlue">Blue</label> </li> </ul> </fieldset>
getElementsByName()
方法能够返回三个input元素。可是对于这里的单选按钮来讲namedItem()
方法只会取得第一项(由于每一项的name特性都相同)。document.anchors
包含文档中全部带name特性的<a>
元素document.applets
包含文档中全部的<form>
元素,与document.getElementsByTagName("form")
获得的结果相同document.images
包含文档中全部的<img>
元素,与document.getElementsByTagName("img")
获得的结果相同document.links
包含文档中全部带 href
特性的<a>
元素document.implementation
属性就是为此提供的,与浏览器对DOM的实现直接对应。document.implementation
规定了一个方法,即hasFeature()
。接收两个参数:要检测的DOM功能的名称及版本号。若是支持返回truevar hasXmlDom = docuemnt.implementation.hasFeature("XML", "1.0");
功能 | 版本号 | 说明 |
---|---|---|
Core | 1.0、2.0、3.0 | 基本的DOM,用于描述表现文档的节点树 |
XML | 1.0、2.0、3.0 | Core的XML拓展,添加了对CDATA、处理指令及实体的支持 |
HTML | 1.0、2.0 | XML的HTML拓展,添加了对HTML特有元素及实体的支持 |
Views | 2.0 | 基于某些样式完成文档的格式化 |
StyleSheets | 2.0 | 将样式表关联到文档 |
CSS | 2.0 | 对层叠样式表1级的支持 |
CSS2 | 2.0 | 对层叠样式表2级的支持 |
Events | 2.0, 3.0 | 常规的DOM事件 |
UIEvents | 2.0, 3.0 | 用户界面事件 |
MouseEvents | 2.0, 3.0 | 由鼠标引起的事件(click、mouseover等) |
MutationEvents | 2.0, 3.0 | DOM树变化时引起的事件 |
HTMLEvents | 2.0 | HTML4.01事件 |
Range | 2.0 | 用于操做DOM树种某个范围的对象和方法 |
Traversal | 2.0 | 遍历DOM树的方法 |
LS | 3.0 | 文件与DOM树之间的同步加载和保存 |
LS-Asnyc | 3.0 | 文件与DOM树之间的异步加载和保存 |
Validation | 3.0 | 在确保有效的前提下修改DOM树的方法 |
hasFeature()
方法确实方便,但也有缺点。由于实现者能够自行决定是否与DOM规范的不一样部分保持一致。事实上,想让hasFearture()
针对全部值都有返回true很容易,但返回true有时候也不意味着实现与规范一致。hasFreatrue()
以外,还同时使用能力检测。write()
和writeln()
方法都接收一个字符串参数,即要写入到输出流中的文本。wirte()
会原样写入,而writeln()
则会在字符串的末尾添加一个换行符(n)。在页面加载的过程当中,可使用这两个方法动态的加入内容。open()
和close()
分别用于打开和关闭网页的输出流。若是是在页面加载期间使用write()
或writeln()
方法,则不须要用到这两个方法。application/xml+xhtml
内容类型提供的页面,这两个方法也一样无效。Element
类型用于表现XML或XHTML元素,提供了对元素标签名、子节点及特性的访问。Element
类型具备如下特征:数组
nodeType
的值为1nodeName
的值为元素的标签名nodeValue
的值为null
parentNode
的值可能为Dcoment或ElementElement
、 Text
、 Comment
、 ProcessingInstruction
、 CDATASection
、 EntityReference
nodeName
属性,也能够是使用tagName
属性,这两个属性会返回相同的值。var div = document.getElementById("myDiv"); console.log(div.tagName); // "DIV" console.log(div.nodeName); // "DIV" console.log(div.tagName == div.nodeName); // true
if (element.tagName == "div") { // 不能这样比较,很容易出错 } if (element.tagName.toLowerCase() == "div") { // 推荐这样作(适用于任何文档) }
全部HTML元素都由HTMLElement
类型表示。HTMLElement
类型直接继承自Elment并添加了一些属性。每一个HTML元素中都存在的下列标准特性:浏览器
id
元素在文档中的惟一标识符title
有关元素的附加说明信息,通常经过工具提示条显示出来lang
元素内容的语言代码,不多使用dir
语言的方向值为"ltr"(left-to-right 从左至右)或 "rtl"className
与元素的class特性对应,即为元素指定的CSS类。没有将这个属性命名为class是由于class是ECMAScript的保留字。getAttribute()
、setAttribute()
、 removeAttribute()
。var div = document.getElemntByid("myDiv"); console.log(div.getAttribute("id")); // "myDiv" console.log(div.getAttribute("class")); // "bd" console.log(div.getAttribute("title")); // "Body Text" console.log(div.getAttribute("lang")); // "en" console.log(div.getAttribute("dir")); // "ltr"
getAttribute()
的特性名与实际的特性名相同。所以想要获得class特性值,应该传入"class" 而不是"className",后者只在经过对象属性访问特性时才用。getAttribute()
返回null
。HTMLElement
也会有5个属性与相应的特性一一对应。不过只有公认的(非自定义)特性才会以属性的形式添加到DOM对象中。例如能够经过div.id
访问div元素的id属性。不过自定义特性在Safari、Opera、Chrome、Firefox中是不存在的,但IE却会为自定义特性也建立属性。getAttribute()
访问时,返回的style特性值中包含的是CSS文本,而经过属性来访问它则会返回一个对象。因为style属性是用于以编程方式访问元素样式的(本章后面讨论),所以并无直接映射到style特性。getAttribute()
访问,返回的是相应的代码字符串。而在访问onclick属性时,则返回的是一个JavaScript函数(若是未在元素中指定相应特性,则返回null
)。这是由于onclick及其余事件程序属性自己就应该被赋予函数值。getAttribute()
方法,而只是使用对象的属性。只有在取得自定义特性值得状况下,才会使用getAttribute()
方法。getAttribute()
访问style特性或onclick,返回的值与属性相同,都返回对象值或函数值。虽然IE8已经修复了这个bug,但不一样IE版本间的不一致性,也是致使开发人员不适用getAttribute()
访问HTML特性的一个缘由。getAttribute()
对应的方法时setAttribute()
这个方法接收两个参数:要设置的特性名和值。若是特性已经存在,setAttribute()
会以指定的值替换现有的值;若是特性不存在,则建立该属性并设置相应的值。setAttribute()
方法既能够操做HTML特性也能够操做自定义特性。经过这个方法设置的特性名会统一转换为小写形式,即"ID"最终变成"id"。div.setAttribute("id", "someOtherId"); div.id = "someOtherId"; // 添加自定义属性,该属性不会自动成为元素的特性 div.mycolor = "red"; div.getAttribute("mycolor"); // null ie除外
removeAttribute()
用于完全删除元素的特性,调用这个方法不只会清楚特性的值,并且也会从元素中彻底删除特性。这个方法并不经常使用,IE6及之前版本不支持。div.removeAttribute("class");
NamedNodeMap
,与NodeList
相似,也是一个动态集合。元素的每个 特性都由一个Attr
节点表示,每一个节点都保存在NamedNodeMap
对象中。NamedNodeMap
对象拥有如下方法缓存
getNamedItem(name)
:返回nodeName
属性等于name
的节点removeNamedItem(name)
:从列表中移除nodeName
属性 等于name的节点setNameItem(node)
:向列表中添加节点,以节点的nodeName
属性为索引item(pos)
:返回位于数字pos位置处的节点attributes
属性中包含一系列节点,每一个节点的nodeName
就是特性的名称,而节点的nodeValue
就是特性的值。// 取得元素的id var id = element.attributes.getNamedItem("id").nodeValue; // 设置元素的id element.attributes["id"].nodeValue = "someOtherId"; // 删除元素id,并返回被删除特性的Attr节点 var oldAttr = element.attributes.removeNamedItem("id"); // 传入一个新的特性节点 element.attributes.setNameItem(newAttr);
getAttribute()
、removeAttribute()
、setAttribute()
方法。若是想要遍历元素特性,能够用attributes// 迭代元素的每个特性,而后构形成 name="value"字符串 function outputAttributes(element) { var pairs = new Array(), attrName, attrValue, i, len; for (i=0, len=elment.attributes.length; i < len; i++) { attrName = element.attributes[i].nodeName; attrValue = element.attributes[i].nodeValue; // 针对 IE7- 作兼容 // 根据specified属性,只返回指定的特性 if (element.attributes[i].specified) { paris.push(attrName + "=\"" + attrValue + "\""); } } return pairs.join(" "); }
document.createElement()
方法能够建立新元素。只接收一个参数,即要建立元素的标签名,在HTML文档中不区分大小写,而在XML(包括XHTML)文档中,则是区分大小写。document.createElement()
建立元素的同时,也为新元素设置了ownerDcoument
属性。此时还能够操做元素的特性,为它添加更多子节点。appendChild()
insertBefore()
replaceChild()
方法。// 建立 var div = document.createElement("div"); // 操做元素特性,添加子节点 div.id = "myNewDiv"; div.className = "box"; document.body.appendChild(div);
在IE中能够传入完整的元素标签,也能够包含属性(仅IE支持)。这样有助于避开在IE7及更早版本中动态建立元素的某些问题:
<iframe>
元素的name
特性reset()
方法重设动态建立的<input>
元素(第13章讨论reset()方法)type
特性值为“reset”的<button>
元素重设不了表单name
相同的单选按钮彼此毫无关系。if (client.browser.id && client.browser.ie <= 7) { var div = document.createElement("<div id=\"myNewDiv\" class=\"box\"></div>"); }
childNodes
属性中包含了它全部子节点,这些子节点多是元素、文本节点、注释或处理指令。不用浏览器在看待这些节点方面存在显著的不一样。<ul id="myList"> <li>item 1</li> <li>item 2</li> <li>item 3</li> </ul>
<ul>
元素会有3个子节点,分别是3个<li>
元素。但若是是其余浏览器,<ul>
元素都会有7个元素,包括3个<li>
元素和4个文本节点(表示<li>
元素之间的空白符)。<ul id="myList"><li>item 1</li><li>item 2</li><li>item 3</li></ul>
childNodes
属性遍历子节点,那么必定不要忘记浏览器间的这一差异。这意味着在执行某项操做之前,一般都要先检查nodeType
属性for (var i=0, len = element.childNodes.length; i < len; i++) { if (element.childNodes[i].nodeTpe == 1) { ... } }
getElementsByTagName()
方法,结果只会返回当前元素的后代。var ul = document.getElementById("myList"); var items = ul.getElementsByTagName("li");
Text节点具备如下特征:
nodeType
的值为3nodeName
的值为'#text'nodeValue
的值为节点所包含的文本parentNode
是一个ElementnodeValue
属性或data
属性访问Text节点中包含的文本,这两个属性的值相同。对nodeValue
的修改也会经过data
反映出来,反之亦然。使用下列方法能够操做节点中的文本
appendData(text)
:将text添加到节点的末尾deleteData(offset, count)
:从offset指定的位置插入textinsertData(offset, text)
:在offset指定的位置插入textreplaceData(offset, count, text)
:用text替换从offset指定的位置开始到 offset+count为止处的文本splitText(offset)
:从offset指定的位置将当前文本节点分红两个文本节点。substringData(offset, count)
:提取从offset指定的位置开始到 offset+count为止处的字符串length
属性:保存着节点中字符的书目。并且nodeValue.length
和data.length
中也保存着一样的数值<!-- 没有内容,也就没有文本节点 --> <div></div> <!-- 有空格,由于有一个文本节点 --> <div> </div> <!-- 有内容,由于有一个文本节点 --> <div>Hello World!</div>
// 能够像这样取得文本子节点 var textNode= div.firstChild; // 或者 div.childNodes[0] // 取得文本节点的引用后,就能够修改它了 div.firstChild.nodeValue = "Some other message";
div.firstChild.nodeValue = "Some <strong>other</strong> message"; // 输出结果:"Some <strong>other</strong> message"
document.createTextNode()
建立新的文本节点。与设置已有文本节点的值同样,做为参数的文本也将按照HTML或XML的格式进行编码。var textNode = document.createTextNode("<strong>Hello</strong> World!");
ownerDocument
属性。不过除非把新节点添加到文档树中已经存在的节点中,不然咱们不会在浏览器窗口中看到新节点。var element = document.createElement("div"); elment.className = "message"; var textNode = document.createTextNode("Hello world!"); element.appendChild(textNode); document.body.appendChild(element);
var element = document.createElement("div"); elment.className = "message"; var textNode = document.createTextNode("Hello world!"); element.appendChild(textNode); var anotherTextNode = document.createTextNode("Yippee!"); element.appendChild(anotherTextNode); document.body.appendChild(element);
normalize()
方法是由Node
类型定义的(于是在全部节点类型中都存在)。若是在一个包含多个文本节点的父元素上调用normalize()
方法,则会将全部文本节点合并成一个文本节点。var element = document.createElement("div"); elment.className = "message"; var textNode = document.createTextNode("Hello world!"); element.appendChild(textNode); var anotherTextNode = document.createTextNode("Yippee!"); element.appendChild(anotherTextNode); document.body.appendChild(element); console.log(element.childNodes.length); // 2 element.normalize(); console.log(element.childNodes.length); // 1 console.log(element.firstChild.nodeValue); // "Hello World!Yippee!"
normalize()
有时候会致使IE6崩溃,IE7以上修复了此问题。splitText()
方法会将一个文本节点分割成两个。var element = document.createElement("div"); elment.className = "message"; var textNode = document.createTextNode("Hello world!"); element.appendChild(textNode); document.body.appendChild(element); var newNode = element.firstChild.splitText(5); console.log(element.firstChild.nodeValue); // "Hello" console.log(newNode.nodeValue); // " World!" console.log(element.childNodes.length); // 2
注释在DOM中是经过Comment类型来表示的。Comment
节点具备如下特征:
nodeType
的值为8nodeName
的值为 "#comment"nodeValue
的值是注释的内容parentNode
多是Dcoment或ElementsplitText()
以外的全部字符串操做方法。<div id="myDiv"><!--A comment--></div>
var div = document.getElementById("myDiv"); var comment = div.firstChild; console.log(comment.data); // "A comment"
document.createComment()
并为其传递注释文本也能够建立注释节点var comment = document.createComment("A comment ");
</html>
标签后的注释。若是要访问注释节点,必定要保证它们是位于<html>
和</html>
之间。splitText()
以外的全部字符串操做方法。CDATASection节点具备下列特征:
nodeType
的值为4nodeName
的值为"#cdata-section"nodeValue
的值是CDATA区域中的内容parentNode
多是Document
或Element
<div id="myDiv"><![CDATA[This is some content.]]></div>
document.createCDataSection()
来建立CDATA区域。DocumentType类型在Web浏览器中并不经常使用,仅有 Firefox Safari 和 Opera支持它。
nodeType
的值为10nodeName
的值为doctype的名称nodeValue
的值是null
parentNode
是Document
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
console.log(document.doctype.name); // "HTML"
document.doctype
的值始终都是null
DOM规定文档片断(document fragment)是一种轻量级的文档,能够包含和控制节点,但不会像完整的文档那样占用额外的资源。
nodeType
的值为11nodeName
的值为"#document-fragment"nodeValue
的值是null
parentNode
是null
Element
、ProcessingInstruction
、Comment
、Text
、 CDATASection
、EntityReference
document.createDocumentFragment()
方法建立文档片断<ul id="myList"></ul>
var fragment = document.createDocumentFragment(); var ul = document.getElementById("myList"); var li = null; // 若是直接向ul添加li元素会致使浏览器反复渲染 // fragment做为一个元素中转的仓库避免了这个问题 for (var i=0; i < 3; i++) { li = document.createElement("li"); li.appendChild(document.createTextNode("Item " + (i+1))); fragment.appendChild(li); } // 这里只会将fragment的全部子节点添加到ul上 // 而fragment自己永远不会成为文档树的一部分 ul.appendChild(fragment);
元素的特性在DOM中以Attr类型来表示。在全部浏览器中(包括IE8),均可以访问 Attr类型的构造函数和原型。
nodeType
的值为2nodeName
的值就是特性的名称nodeValue
的值就是特性的值parentNode
是null
name
value
specified
。document.createAttribute()
传入特性的名称能够建立新的特性节点。var attr = document.createAttribute("align"); attr.value = "left"; element.setAttribute(attr); console.log(element.attributes["align"].value); // left console.log(element.getAttributeNode("align").value); // left console.log(element.getAttribute("align")); // left
<script>
元素能够向页面中插入JavaScript代码,一种是经过其src特性包含外部文件,另外一种就是用这个元素自己包含代码。// 在执行最后一行代码把<script>元素添加到页面中以前 // 是不会下载外部文件的 var script = document.createElement("script"); script.type = "text/javascript"; script.src = "client.js"; document.body.appendChild(script);
<script type="text/javascript" src="client.js"></script>
<script>
视为一个特殊元素,不容许DOM访问其子节点。不过可使用<script>
元素的text属性来制定JavaScript代码var script = document.createElement("script"); script.type = "text/javascript"; // 这样IE不支持 script.appendChild( document.createTextNode("function sayHi() { console.log('Hi')}") ); // 可使用`<script>`元素的text属性来制定JavaScript代码 script.text = "function sayHi() { console.log('Hi')}"; document.body.appendChild(script);
var script = document.createElement("script"); script.type = "text/javascript"; var code = "function sayHi() { console.log('Hi')}" try { script.appendChild(document.createTextNode(code)); } catch (ex) { script.text = code; } document.body.appendChild(script);
eval()
是同样的。var link = document.createElement("link"); link.rel = "stylesheet"; link.type = "text/css"; link.href = "style.css"; var head = document.getElementsByTagName("head")[0]; head.appendChild(head);
<link rel="stylesheet" type="text/css" href="styles.css">
<link>
元素添加到<head>
而不是<body>
元素,才能保证所在浏览器中的行为一致。function loadStyleString(css) { var style = document.createElement("style"); style.type = "text/css"; try { style.appendChild(document.createTextNode(css)); } catch (ex) { style.styleSheet.cssText = css; } document.getElementsByTagName("head")[0].appendChild(style); }
styleSheet.cssText
属性。在重用同一个<style>
元素并再次设置这个属性时,有可能致使浏览器崩溃。一样将cssText
属性设置为空字符串也可能致使浏览器崩溃。<table>
元素是HTML中最复杂的结构之一。想要建立表格,通常都必须涉及表示表格行、单元格、表头等方面。因为涉及的标签多,于是使用核心DOM方法建立和修改表格每每都免不了要编写大量的代码。<table border="1" width="100%"> <tbody> <tr> <td>Cell 1,1</td> <td>Cell 2,1</td> </tr> <tr> <td>Cell 1,2</td> <td>Cell 2,2</td> </tr> </tbody> </table>
// 使用核心DOM方法建立这些元素 // 建立table var table = document.createElement("table"); table.border = 1; table.width = "100%"; // 建立tbody var tbody = document.createElement("tbody"); table.appendChild(tbody); // 建立第一行 var row1 = document.createElement("tr"); tbody.appendChild(row1); var cell1_1 = document.createElement("td"); cell1_1.appendChild(document.createTextNode("Cell 1,1")); row1.appendChild(cell1_1); var cell2_1 = document.createElement("td"); cell2_1.appendChild(document.createTextNode("Cell 2,1")); row1.appendChild(cell2_1); // 建立第二行 var row2 = document.createElement("tr"); tbody.appendChild(row2); var cell1_2 = document.createElement("td"); cell1_2.appendChild(document.createTextNode("Cell 1,2")); row2.appendChild(cell1_2); var cell2_2 = document.createElement("td"); cell2_2.appendChild(document.createTextNode("Cell 2,2")); row2.appendChild(cell2_2); // 将表格添加到文档主体中 document.body.appendChild(table);
<table>
<tbody>
<tr>
元素添加了一些属性和方法。<table>
元素添加的属性和方法:
<caption>
元素(若是有)的指针<tbody>
元素的HTMLCollction<tfoot>
元素的(若是有)指针<thead>
元素的(若是有)指针<thead>
元素,将其放到表格中,返回引用<tfoot>
元素,将其放到表格中,返回引用<caption>
元素,将其放到表格中,返回引用<thead>
元素<tfoot>
元素<caption>
元素rows
集合中的指定位置插入一行为<tbody>
元素添加的属性和方法以下:
<tbody>
元素中行的HTMLCollectionrows
集合中的指定位置插入一行为<tr>
元素添加的属性和方法以下:
<tr>
元素中单元格的HTMLCollectioncells
集合中的指定位置插入一个单元格,返回对新插入单元格的引用。// 根据以上属性和方法,能够大大简化前述代码 // 建立table var table = document.createElement("table"); table.border = 1; table.width = "100%"; // 建立tbody var tbody = document.createElement("tbody"); table.appendChild(tbody); // 建立第一行 tbody.insertRow(0); tbody.rows[0].insertCell(0); tbody.rows[0].cells[0].appendChild(document.createTextNode("Cell 1,1")); tbody.rows[0].insertCell(1); tbody.rows[0].cells[1].appendChild(document.createTextNode("Cell 2,1")); // 建立第二行 tbody.insertRow(0); tbody.rows[1].insertCell(0); tbody.rows[1].cells[0].appendChild(document.createTextNode("Cell 1,2")); tbody.rows[1].insertCell(1); tbody.rows[1].cells[1].appendChild(document.createTextNode("Cell 2,2")); // 将表格添加到文档主体中 document.body.appendChild(table);
NodeList
及其近亲 NamedNodeMap
和 HTMLCollection
,是从总体上透彻理解DOM的关键所在。这三个集合都是动态的,每当文档结构发生变化,它们都会获得更新。NodeList
对象都是在访问DOM文档实时运行的查询。// 下列代码会致使无限循环 var divs = document.getElementsByTagName("div"); var div; // 每次循环都要对条件 i < divs.length 求值 // 但每次循环都添加了一个新的div for (var i=0; i < divs.length; i++) { div = document.createElement("div"); document.body.appendChild(div); }
// 最好使用length属性初始化第二个变量 var divs = document.getElementsByTagName("div"); var i, len, div; // len保存着第一次循环时div的数量,不会随着循环增长 for (i=0, len=divs.length; i < len; i++) { div = document.createElement("div"); document.body.appendChild(div); }
NodeList
的次数,由于每次访问都会运行一次基于文档的查询。能够考虑将从NodeList
中取得的值缓存起来。