概述
DOM全称Document Object Model,即文档对象模型。是HTML和XML文档的编程接口,DOM将文档(HTML或XML)描绘成一个多节点形成的构造。应用JavaScript能够扭转文档的构造、款式和内容。
W3C DOM
由以下三局部组成:
外围DOM
- 针对任何结构化文档的规范模型。XML DOM
- 针对XML
文档的规范模型。HTML DOM
- 针对HTML
文档的规范模型。
分类
DOM目前有三种级别:
- DOM Level 1:1998年10月成为W3C的举荐规范,次要定义HTML和XML文档的底层构造。
- DOM Level 2: 在DOM1根底上裁减了办法和属性,引入了与文档更多的交互能力。次要包含DOM视图、DOM款式、DOM事件、DOM遍历和范畴等。
- DOM Level 3:引入了将XML文档加载和序列化的办法。提供了验证文档有效性的能力。
节点树
以上面的HTML为例:
<html><head> <meta charset="UTF-8"> <title>节点树</title></head><body> <div>测试块</div> <a href="/about">链接</a></body></html>
浏览器会将HTML文档解析成节点并组成节点树。
HTML DOM中通过不同类型节点来示意, Document
是每个文档的根节点。这里的document
只有一个<html>
子节点,称之为文档元素(Element
)。Element
示意元素类型的节点,Text
示意文本类型的节点。
节点类型
DOM 的最小组成单位叫做节点(node)。下面的节点树中,每一段都由不同类型的节点组成。节点的类型有如下几种:
Node
:浏览器提供的原生节点,上面的节点都继承它。Document
:整个文档树的顶层节点DocumentType
:doctype
标签(比方<!DOCTYPE html>
)。Element
:网页的各种HTML标签(比方<body>
、<a>
等)。Attr
:网页元素的属性(比方class="right"
)。Text
:标签之间或标签蕴含的文本。Comment
:正文。CDATASection
:CDATA
区域,与Comment
类型相似。DocumentFragment
:文档的片段。
Node
DOM1中定义了一个Node
接口,JavaScript中所有节点类型都继承自Node
类型,因而属性和办法都雷同。
在Node
类型中定义了nodeType
属性来表明节点的类型,由12个常量示意。任何节点必居其一:
Node.ELEMENT_NODE
:数值1,对应元素节点Element
。Node.ATTRIBUTE_NODE
:数值2,对应属性节点Attr
。Node.TEXT_NODE
:数值3,对应文本节点Text
。Node.CDATA_SECTION_NODE
:数值4,对应文档中CDATA部(不会由解析器解析的文本)。Node.ENTITY_REFERENCE_NODE
:数值5,对应实体援用。Node.ENTITY_NODE
:数值6,对应实体类型Entity
。Node.PROCESSING_INSTRUCTION_NODE
:数值7,对应解决指令。Node.COMMENT_NODE
:数值8,对应正文节点Comment
。Node.DOCUMENT_NODE
:数值9,对应文档节点Document
。Node.DOCUMENT_TYPE_NODE
:数值10,对应文档类型节点DocumentType
。Node.DOCUMENT_FRAGMENT_NODE
:数值11,对应文档片段节点DocumentFragment
。Node.NOTATION_NODE
:数值12,对应DTD中申明的符号。
应用nodeType
能够很容易确定节点类型,IE
中没有公开Node
类型的构造函数,应用Node.ELEMENT_NODE
比拟会导致谬误。为了兼容IE
,能够应用数值进行比拟:
if (onenode.nodeType == Node.ELEMENT_NODE) { // 在IE中有效 console.log("The Node is an Element.");}// 或者if (oneNode.nodeType == 1) { // 实用所有浏览器 console.log("The Node is an Element.");}
nodeName
返回节点的标签名
var div = document.getElementByTagName('div')[0];console.log(onenode.nodeName); // DIV
nodeValue
返回字符串,示意节点的文本值,可读写。
var div = document.getElementByTagName('div')[0];console.log(onenode.nodeValue); // null
节点关系
文档中节点都存在着肯定的关系,节点之间的关系能够应用相似人类家族关系的模式形容。如,在HTML文档中,能够把<html>
看作是<body>
的父元素;绝对的,<body>
也就是<html>
的子元素;而作为<body>
同级的<head>
两者之间的关系为兄弟(姐妹)关系。
Node
中提供了几种节点遍历的属性:parentNode
、childNodes
、firstNode/lastNode
、previousSibling/nextSibling
、ownerDocument
。
Document
JavaScript通过Document
类型示意文档。浏览器中的document
对象是HTMLDocument
的一个实例,示意整个HTML页面。Document
节点具备以下特色:
nodeType
为Node.DOCUMENT_NODE
,值为9。nodeName
的值为#document
。nodeValue
的值为null
。parentNode
的值为null
。ownerDocument
的值为null
。- 其子结点可能是一个
DocumentType
、Element
、ProcessingInstruction
或Comment
。
document
对象还有一些属性来示意网页的一些信息:
title
:获得以后页面的题目,也能够批改以后页面的题目并反映在浏览器的标题栏中。但不会扭转<title>
元素。URL
:蕴含页面残缺的URL
。domain
:只蕴含页面的域名。referrer
:保留着链接到以后页面的那个页面的URL
。没有起源页面的状况下,可能蕴含空字符串。
URL
与domain
属性是互相关联的。
Element
Element类型用于体现XML或HTML元素,提供对元素标签名、子节点及个性的拜访。例如<body>
和<div>
等。Element
节点具备以下特色:
nodeType
为Node.ELEMENT_NODE
,值为1。nodeName
的值为元素的标签名。nodeValue
的值为null
。parentNode
可能是Document
或Element
。- 其子节点可能是
Element
、Text
、Comment
、ProcessingInstruction
、CDATASection
或EntityReference
。
要拜访元素的标签名,能够应用nodeName
属性,也能够应用tagName
属性;这两个属性会返回雷同值。
获取<div id="divId"></div>
的标签名:
var div = document.getElementById("divId");console.log(div.tagName); // DIVconsole.log(div.tagName == div.nodeName); // true
个性和属性
所有HTML元素都由HTMLElement
类型示意,不能间接通过这个类型,也是通过它的子类型来示意。HTMLElement
类型间接继承自Element
并增加了一些属性。每个HTML元素中的个性(例如<div id="d1" title="附加信息" lang="en" class="container">
中的id
、class
等)会主动变成DOM对象的属性(class
个性与className
属性对应)。这些都能够通过div.id
等获取并赋值。
一个元素中的id
等是规范的个性,但也有非标准的个性不能应用div.id
形式获取。那么要用什么办法来拜访非个性。
DOM
次要提供了几个办法用于对任何个性进行操作,别离是:
hasAttribute(qualifiedName: string)
,查看qualifiedName
这个个性是否存在。getAttribute(qualifiedName: string)
,获取qualifiedName
这个个性值,如果不存在,则返回null
。setAttribute(qualifiedName: string, value: string)
,设置qualifiedName
这个个性的值为value
。设置的个性名会被批准转换为小写模式。removeAttribute(qualifiedName: string)
,移除qualifiedName
这个个性。
<div id="d1" title="附加信息" lang="en" class="container main" plug-add="增加的非标准的个性">
以下面的HTML为例,应用这几种办法。
var div = document.getElementById('d1');div.getAttribute('title'); // 附加信息div.hasAttribute('plug-add'); // truediv.setAttribute('title', '批改附加信息');div.removeAttribute('plug-add');
有两类非凡的个性,虽有对应的属性名,但属性的值与getAttribute()
返回的值并不相同。
第一类个性就是style
,用于通过CSS为元素指定款式。通过getAttribute()
返回的style
中蕴含的是CSS文本,而通过属性返回的是一个对象。
第二类个性是onclick
这样的事件处理。如果通过getAttribute()
返回的是相应代码的字符串。而拜访onclick
属性返回的是JavaScript函数(如果未指定相应个性,返回的是null
)。
attributes属性
Element
类型的attributes
属性返回该元素所有属性节点的一个汇合,该汇合是一个"动静"的NamedNodeMap
对象。NamedNodeMap
对象领有下列办法。
getNamedItem(name)
:返回nodeName
属性等于name
的节点。removeNamedItem(name)
:从列表中移除nodeName
属性等于name
的节点。setNamedItem(node)
:向列表中增加节点,以节点的nodeName
属性为索引。item(pos)
:返回位于数字pos
地位处的节点。
attributes
属性蕴含一系列节点,在节点中节点名称-nodeName 节点值-nodeValue
。
var id = element.attributes.getNamedItem('id').nodeValue;// 方括号语法var id = element.attributes['id'].nodeValue;// 属性名援用var id = element.attributes.id;// 如果晓得个性名所在的下标,也能够应用下标援用,假如id个性名所在下标为0.var id = element.attributes[0];
而removeNamedItem()
办法与removeAttribute()
办法都是将给定名称的个性删除,惟一区别就是removeAttribute()
没有返回值,removeNamedItem()
返回被删除个性的Attr
节点。
var oldAttr = element.attributes.removeNamedItem('id');
setNamedItem()
办法为Element
增加一个新个性:
element.attributes.setNamedItem(newAttr);
个别状况下getAttribute()
、removeAttribute()
和setAttribute()
办法就够应用了,但想要遍历元素的个性,attributes
属性倒是比拟不便。上面展现如果迭代元素中每一个个性并将它们以name="value" name="value"
这样的字符串格局。
function listAttributes(element) { var pairs = new Array(), attrName, attrValue, i, len; if (element.hasAttributes()) { var attrs = element.attributes; for (i = 0, len = element.attributes.length; i < len; i++) { attrName = attrs[i].nodeName; attrValue = attrs[i].nodeValue; pairs.push(attrName + "=\"" + attrValue + "\""); } } return pairs.join(" ");}
classList
className
属性用于操作类名,但className
是一个字符串,批改后要设置整个字符串的值。
HTML5扩大了classList
属性实现类名的操作。该属性返回DOMTokenList
汇合。定义了几个办法:
add(value)
:增加字符串到列表中。如果存在就不增加。contains(value)
:指定值是否存在于列表中,存在则为true
,否则为false
。remove(value)
:从列表中删除指定值。toggle(value)
:列表中存在指定值,删除它;没有给定值,增加它。
Attr
Attr
类型在DOM
示意元素个性。个性是位于元素attributes
属性中的节点。具备下列特色:
nodeType
为Node.TEXT_NODE
,值为3。nodeName
的值是个性的名称。nodeValue
的值是个性的名称。parentNode
的值为null
。- 在HTML中不反对子节点(没有子节点)。
- 在XML中子节点能够是
Text
或EntityReference
。
个性节点不被认为是DOM
文档树的一部分。最常应用getAttrubute()
、setAttribute()
和removeAttribute()
办法,很少间接援用个性节点。
Attr
对象有3个属性:
name
,个性名称,与nodeName
的值雷同。value
,个性值,与nodeValue
的值雷同。specified
,布尔值,用于辨别个性在代码中是指定的还是默认的。
如果要为元素增加个性,能够应用document.createAttribute(localName)
办法,创立名为localName
的个性节点。例如,要为元素增加align
个性,能够应用下列代码:
var attr = document.createAttribute("align");attr.value = "left";element.setAttributeNode(attr);alert(element.attributes["align"].value); //"left"alert(element.getAttributeNode("align").value); //"left"alert(element.getAttribute("align")); //"left"
Text
文本节点由Text
类型示意,蕴含的是能够照字面解释的纯文本内容。纯文本中能够蕴含本义后的HTML字符,但不能蕴含HTML代码。Text
节点具备以下特色:
nodeType
为Node.TEXT_NODE
,值为3。nodeName
的值为#text
。nodeValue
的值为节点所蕴含的文本。parentNode
是一个Element
。- 不反对子节点(没有子节点)。
能够通过nodeValue
属性或data
属性拜访Text
节点中蕴含的文本,这两个属性中蕴含的值雷同。对nodeValue
的批改也会通过data
反映进去,反之亦然。应用下列办法能够操作节点中的文本。
appendData(text)
:将text
增加到节点的开端。deleteData(offset, count)
:从offset
指定地位开始删除count
个字符。insertData(offset, text)
:在offset
指定地位插入text
。replaceData(offset, count, text)
:用text
替换从offset
指定的地位开始到offset
+count
地位处的文本。splitText(offset)
:从offset
指定的地位将以后文本节点分成两个文本节点。substringData(offset, count)
:提取从offset
指定的地位开始到offset
+count
为止处的字符串。
除了这些办法外,文本节点还有一个length
属性,保留着节点中字符的数目。而且,nodeValue.length
和data.length
中也保留着同样的值。
批改文本节点的后果会立刻失去反映。因而字符串会通过HTML(或XML,取决于文档类型)编码。
应用document.createTextNode()
能够创立文本节点,在DOM创立
中会讲述它。
Comment
正文在DOM中是通过Comment
类型来示意的。Comment
节点具备下列特色:
nodeType
为Node.COMMENT_NODE,数值为8。nodeName
的值为#comment
。nodeValue
的值是正文的内容。parentNode
可能是Document
或Element
。- 不反对子节点(没有子节点)。
Comment
类型与Text
类型继承自雷同的基类,因而它领有除splitText()
之外的所有字符串操作方法。与Text
类型类似,也能够通过nodeValue
或data
属性获得正文的内容。
获取<div id="divId"><!--A comment--></div>
代码中的正文:
var div = document.getElementById("divId");var comment = div.firstChild;console.log(comment.data); // A comment
如果想创立正文节点,能够应用document.createComment(data)
办法创立。
var comment = document.createComment("Create a comment node");
浏览器不会辨认位于</html>
标签前面的正文。肯定保障拜访的正文节点位于<html></html>
之间。
CDATASection
CDATASection
类型只针对基于XML文档,示意的是CDATA
区域。与Comment
相似,CDATASection
类型继承自Text
类型,因而领有除splitText()
之外的所有字符串操作方法。CDATASection
节点具备以下特色:
nodeType
为CDATA_SECTION_NODE
,值为4。nodeName
的值为#cdata-section
。nodeValue
的值是CDATA
区域中的内容。parentNode
可能是Document
或Element
。- 不反对子节点(没有子节点)。
CDATA
区域只会呈现在XML文档中,因而少数浏览器都会把CDATA
区域谬误地解析为Comment
或Element
。以上面的代码为例:
<div id="divId"><![CDATA[This is content.]]></div>
这个例子中的<div>
元素应该蕴含一个CDATASection
节点。可是,四大支流浏览器无一可能这样解析它。即便对于无效的XHTML页面,浏览器也没有正确地反对嵌入的CDATA
区域。
在真正的XML文档中,能够应用document.createCDataSection()
来创立CDATA
区域,只需为其传入节点的内容即可。
DocumentType
DocumentType
类型在Web浏览器中并不罕用。DocumentType
蕴含着与文档无关的doctype
无关的所有信息,它具备下列特色:
nodeType
为Node.DOCUMENT_TYPE_NODE
,值为10。nodeName
的值为doctype
的名称。nodeValue
的值为null
。parentNode
是Document
类型。- 没有子节点。
DOM 1级
规定的DocumentType
对象不能动态创建,只通过解析文档代码的形式来创立。反对DocumentType
的浏览器会把它保留在document.doctype
中。
DocumentType
对象在DOM 1级
中有3个属性:
DocumentType.name
,文档类型的名称。DocumentType.entities
,文档类型形容的实体NamedNodeMap
对象。DocumentType.notations
,文档类型形容的符号NamedNodeMap
对象。
浏览器中个别是HTML
或XHTML
类型的文档。所以entities
和notations
都是空列表。只有name
属性有用。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
在这里,DocumentType
中的name
属性保留的就是HTML
。
console.log(document.doctype.name); // HTML
DocumentFragment
DocumentFragment
是文档片段,一种"轻量级"文档,能够蕴含和管制节点,但不像残缺文档那样占用额定资源。能够将它作为"仓库"应用。具备下列特色:
nodeType
为Node.DOCUMENT_FRAGMENT_NODE
,值为11。nodeName
的值为#document-fragment
。nodeValue
的值为null
。parentNode
的值为null
。- 子节点能够是
Element
、ProcessingInstruction
、Comment
、Text
、CDATASection
或EntityReference
。
应用document.createDocumentFragment()
办法创立文档片段,如下所示:
var fragment = document.createDocumentFragment();
继承了Node
的所有办法,用于执行针对文档的DOM
操作。能够通过appendChild()
或insertBefore()
增加到文档中相应地位,但自身不会成为文档树的一部分。来看上面的HTML 示例代码:
<ul id="ulId"></ul>
咱们给<ul id=ulId></ul>
增加3个列表项。能够应用文档片段来保留创立的列表项,一次性将它们增加到文档中,防止浏览器重复渲染。
var fragment = document.createDocumentFragment();var ul = document.getElementById("myList");var li = null;for (var i=0; i < 3; i++){ li = document.createElement("li"); li.appendChild(document.createTextNode("Item" + (i+1))); fragment.appendChild(li);}ul.appendChild(fragment);
DOM查找
当初有一段html
页面模板
...<style> .container { background-color: blue; width: 55%; height: 55%; }</style>...<div class="container" id="divId1">Div Text One</div><p class="container" id="pId1">P Text One</p><a class="container" id="aId1">A Text One</a><div class="container" id="divId2">Div Text Two</div><form id="primary-form" action="#" method="get"> <p>UserName: <input type="text" name="input-name"></p> <p class="container">NickName: <input type="text" name="input-name"></p> <p>Email: <input type="text" name="input-email"></p> <input type="submit" value="Submit"></form>...
在该模板中,咱们想要获取这些标签元素,能够应用document
对象获取的几种办法:
id选择器
getElementById(elementId: string): HTMLElement | null;
该办法返回匹配指定id
属性的元素节点,如果不存在,则返回null
。
上面通过id
选择器来获取id
为aId1
的元素:
let div = document.getElementById("aId1");console.log(div); // <a class="container" id="aId1">A Text One</a>
留神:严格匹配,包含大小写。如果写成document.getElementById("aid1")
,输入为null
。
标签选择器
getElementsByTagName(qualifiedName: string): HTMLCollectionOf<Element>;
该办法返回匹配指定HTML标签名的元素列表。返回的是一个相似数组对象(HTMLCollection
实例),能够实时反映HTML文档的变动,如果不存在,则返回null
。
let inputs = document.getElementsByTagName('input');console.log(inputs); /* HTMLCollection(4) [input, input, input, input, input-name: input, email: input]*/
这个对象能够应用length
属性获取元素数量,应用数组语法或item()
办法来拜访HTMLCollection对象中的项。
inputs.length; // 输入p标签的数量inputs[0].id; // 输入p标签汇合中第一个元素的id个性的名称inputs.item(0).className; // 输入p标签接种中第一个元素的class个性的名称
还能够通过namedItem()
办法依据元素的name
个性获取汇合中的项。
var nameOfInput = inputs.namedItem("input-name");
也能够应用方括号语法来拜访:
var nameOfInput = inputs["input-name"];
要想获得文档中的所有元素,能够向getElementsByTagName()中传入"*"
,示意"全副"。
var allElements = document.getElementsByTagName("*");
name选择器
getElementsByName(elementName: string): NodeListOf<HTMLElement>;
该办法返回匹配name
属性的所有元素,返回值是NodeList
,如果不存在,则返回null
。
var names = document.getElementsByName("input-name");console.log(names);
留神,这个选择器在不同浏览器的成果是不同的,比方在IE和Opera浏览器下,这个办法也会返回id
属性为这个值的元素。在应用的时候,应该小心应用,尽量保障name
不和其它元素的id
统一。
类选择器
getElementsByClassName(classNames: string): HTMLCollectionOf<Element>;
是HTML5中增加的办法。
该办法返回匹配class
属性的所有元素,返回值是HTMLCollection
,如果不存在,则返回null
。
// 获取所有class中同时蕴含'red'和'test'的元素var classes = document.getElementsByClassName("container");console.log(classes);
能够接管蕴含一个或多个类名的字符串,传入的多个类名的先后顺序不重要。
Selectors API
W3C发动指定的规范,可使浏览器反对CSS查问。Selectors API的外围是两个办法:querySelector()
和querySelectorAll()
。兼容的浏览器中通过Document
及Element
节点类型的实例进行调用。
querySelector()办法
querySelector<E extends Element = Element>(selectors: string): E | null;
该办法返回匹配指定选择符的第一个HTMLElement
元素,如果不存在,则返回null
。传入的selectors
必须是无效的CSS选择器;如果选择器不非法,会引发SYNTAX_ERR
异样。
document.querySelector("#aId1"); // 获得Id为"aId1"的元素document.querySelector("p"); // 获得p元素document.querySelector(".container"); // 获得类为"container"的第一个元素document.querySelector("..selector"); // 引发'SYNTAX_ERR'异样(Uncaught DOMException:Failed to execute 'querySelector on 'Document': '..selector' is not a valid selector. 意思是'..selector'不是一个无效的抉择。)
Document
和Element
都能够调用querySelector()
办法,只是Document
会在文档元素的范畴内查找匹配的元素;Element
只会在该元素后辈元素的范畴内查找匹配的元素。
querySelectorAll()办法
querySelectorAll<E extends Element = Element>(selectors: string): NodeListOf<E>;
该办法返回匹配指定选择符的元素列表,返回的对象是NodeList
,如果不存在,则返回空的NodeList
。传入的selectors
必须是无效的CSS选择器;如果选择器不非法,会引发SYNTAX_ERR
异样。
// 获取id为"primary-form"中所有<p>元素document.getElementById("primary-form").querySelectorAll("p");// 获取类为"container"的所有元素document.querySelectorAll(".container");// 获取所有<form>元素中的所有<p>元素document.querySelectorAll("form p");
matches()办法
Selectors API Level 2标准为Element
类型新增了一个办法:
matches(selectors: string): boolean;
该办法判断以后DOM节点是否能齐全匹配指定选择符,如果匹配胜利,返回true
;匹配失败,返回false
。
var elems = document.getElementsByTagName('p');for (var i = 0; i < elems.length; i++) { // 获取匹配'container'类选择符的dom节点 if (elems.item(i).matches('.container')) { console.log('The ' + elems.item(i).textContent + ' is container'); }}/*The P Text One is containerThe NickName: is container*/
留神,有些供应商会有本人实验性办法在matchesSelector()
办法之前加些前缀。如果想应用这种办法,能够编写一个包装函数。
function matchesSelector(element, selector){ if (element.matches) { // 规范办法 return element.matches(selector); } else if (element.matchesSelector){ return element.matchesSelector(selector); } else if (element.msMatchesSelector){ // IE 9+反对 return element.msMatchesSelector(selector); } else if (element.mozMatchesSelector){ // Firefox 3.6+反对 return element.mozMatchesSelector(selector); } else if (element.webkitMatchesSelector){ // Safari 5+和Chrome反对 return element.webkitMatchesSelector(selector); } else { throw new Error("Not supported."); }}if (matchesSelector(document.body, ".container")){ //执行操作}
当有的浏览器不反对Element.matches()
或Element.matchesSelector()
,但反对document.querySelectorAll()
办法,能够有代替计划:
if (!Element.prototype.matches) { Element.prototype.matches = Element.prototype.matchesSelector || Element.prototype.mozMatchesSelector || Element.prototype.msMatchesSelector || Element.prototype.oMatchesSelector || Element.prototype.webkitMatchesSelector || function(s) { var matches = (this.document || this.ownerDocument).querySelectorAll(s), i = matches.length; while (--i >= 0 && matches.item(i) !== this) {} return i > -1; };}
DOM遍历
Node
节点提供了几种属性,用于拜访DOM节点。
parentNode
node.parentNode
属性用于返回指定节点的父节点。除document
外,所有节点都有父节点,document
对象的父节点为null
。示例如下:
document.getElementById('divId2').parentNode;
childNodes
node.childNodes
属性用于返回指定节点的子结点的Node
对象汇合。示例如下:
document.getElementById('primary-form').childNodes;
firstChild/lastChild
node.firstChild
属性用于拜访第一个子节点;node.lastChild
属性用于拜访最初一个子节点。如果要拜访的节点不存在,则返回null
。示例如下:
document.getElementById('primary-form').firstChilddocument.getElementById('primary-form').lastChild;
previousSibling/nextSibling
node.previousSibling
属性用于拜访之前的同级节点;node.nextSibling
属性用于拜访之后的同级节点。具备雷同父节点为同级节点,之前或之后示意它们在文档中呈现的程序。实例如下:
document.getElementById('divId2').previousSibling;document.getElementById('divId2').nextSibling;
ownerDocument
node.ownerDocument
属性用于返回元素的根节点,即:文档对象(Document
)。通过这个属性,咱们可能间接拜访根节点而不用层层遍历。实例如下:
document.getElementById('divId2').ownerDocument;
Element Traversal
Element Traversal API 为DOM元素增加了以下5个属性。
childElementCount
:返回子元素(不包含文本节点和正文)的格局。firstElementChild
:指向第一个子元素;firstChild
的元素版。lastElementChild
:指向最初一个子元素;lastChild
的元素版。previousElementSibling
:指向前一个同辈元素;previousSibling
的元素版。nextElementSibling
:指向后一个同辈元素;nextSibling
的元素版。
反对的浏览器为DOM元素增加了这些属性,利用这些元素不用放心空白文档节点,从而能够更不便地查找DOM元素。
DOM操作
因为关系节点都是只读的,所以DOM提供了一些操作节点的办法。
appendChild()
node.appendChild(newChild)
办法用于向childNodes
列表的开端增加一个节点并返回新增的节点。
var returnedNode = div.appendChild(newNode);
insertBefore()
node.insertBefore(newChild, refChild)
办法会在指定的参照节点refChild
之前插入新节点newChild
。插入节点后,被插入的节点会变成参照节点的前一个同胞节点(previousSibling
),同时被办法返回。如果refChild
是null
,则insertBefore()
与appendChild()
执行雷同的操作。
var returnedNode = div.insertBefore(newNode, div.lastChild);
replaceChild()
node.replaceChild(newChild, oldChild)
办法将要替换的节点oldChild
移除,并将要插入的节点newChild
插入并占据其地位。实例如下:
document.getElementById('divId2').replaceChild(newnode, oldnode);
在应用replaceChild()
插入一个节点时,该节点的所有关系指针都会从被它替换的节点复制过去。被替换的节点依然还在文档中,但它在文档中曾经没有本人的地位了。
removeChild()
而如果只想移除而非替换节点,能够应用node.removeChild(oldChild)
办法,该办法将要移除的节点oldChild
移除,并返回移除的节点。
var removedNode = node.removeChild(node.firstChild);
与应用replaceChild()
办法一样,通过removeChild()
移除的节点依然为文档所有,只不过在文档中曾经没有了本人的地位。
下面介绍的四种办法操作的都是某个节点的子节点,要应用这几个办法必须先获得父节点。另外,并不是所有类型的节点都有子节点,如果在不反对子节点的节点上调用这些办法,将会导致谬误产生。
DOM创立
DOM节点创立最罕用的便是document.createElement()
和document.createTextNode()
办法。
createElement()
document.createElement(tagName)
办法依据指定tagName
标签名创立新元素节点,返回一个HTMLElement
对象。标签名在HTML文档中不辨别大小写,在XML(包含XHTML)文档中辨别大小写。例如,创立一个<p>
元素。
var p = document.createElement('p');
在应用createElement()
办法创立新元素的同时,也为新元素设置了ownerDocument
属性。
createTextNode()
document.createTextNode(data: string)
办法依据指定data
文本创立新文本节点。作为参数的文本依照HTML或XML的格局进行编码。
var textNode = document.createTextNode("<h4>Hello </h4> world!");
在创立新文本节点的同时,也会为其设置ownerDocument
属性。
cloneNode()
node.cloneNode(deep)
办法用于对调用这个办法的节点创立一个完全相同的正本。deep
是布尔值,设置是否执行深复制。默认为false
,执行浅复制(只复制节点自身);当为true
时,执行深复制(复制节点及其整个子节点树)。
var node = document.getElementById('divId2').lastChild.cloneNode(true);
这些用于创立节点和复制节点的办法,创立或复制的节点并不会呈现在文档中,须要通过appendChild()
、insertBefore()
或replaceChild()
将它增加到文档中。
document.getElementById('divId2').appendChild(node);
不论是createElement()
、createTextNode()
或者cloneNode()
三种的哪种办法,创立新的节点都未被增加到文档树中。能够应用下面介绍的appendChild()
、insertBefore()
或replaceChild()
办法将新节点增加到文档树中。
一旦将节点增加到文档树中,浏览器就会立刻出现。
一旦应用appendChild()
等办法插入相邻的同胞文本节点时,会导致相邻文本节点凌乱。
而在一个蕴含两个或多个文本节点的父元素上调用normalize()
办法,就会将所有文本节点合并成一个节点。
var element = document.createElement("div");element.className = "message";var textNode1 = document.createTextNode("Hello, ");element.appendChild(textNode1);var textNode2 = document.createTextNode("Pandora!");element.appendChild(textNode2);document.body.appendChild(element);console.log(element.childNodes.length); // 2element.normalize();console.log(element.childNodes.length); // 1console.log(element.firstChild.nodeValue); // "Hello, Pandora!"
浏览器在解析文档时永远不会创立相邻的文本节点。这种状况只会作为执行DOM操作的后果呈现。
还有一个与normalize()
相同的办法 splitText(offset)
:将一个文本节点分成两个文本节点。
var element = document.createElement("div");element.className = "message";var textNode = document.createTextNode("Hello, Pandora!");element.appendChild(textNode);document.body.appendChild(element);var newNode = element.firstChild.splitText(6);console.log(element.firstChild.nodeValue); // "Hello,"console.log(newNode.nodeValue); // " Pandora!"console.log(element.childNodes.length); // 2
更多内容请关注公众号「海人为记」