JavaScript HTML DOM文档对象模型之Node类型介绍

237 1 年前
DOM1 级定义了一个 Node 接口,该接口将由 DOM 中的所有节点类型实现。这个 Node 接口在JavaScript 中是作为 Node 类型实现的;JavaScript 中的所有节点类型都继承自 Node 类型,因此所有节点类型都共享着相同的基本属性和方法。

JavaScript中所有HTML DOM节点类型都继承自Node类型,因此所有类型的节点都有一些相同的属性和方法。Node接口是DOM1级中定义的一个接口,在JavaScript中Node接口被实现为Node类型。

节点类型由在 Node 类型中定义的下列 12 个数值常量来表示,任何节点类型必居其一:

常量值 常量名
1 Node.ELEMENT_NODE
2 Node.ATTRIBUTE_NODE
3 Node.TEXT_NODE
4 Node.CDATA_SECTION_NODE
5 Node.ENTITY_REFERENCE_NODE
6 Node.ENTITY_NODE
7 Node.PROCESSING_INSTRUCTION_NODE
8 Node.COMMENT_NODE
9 Node.DOCUMENT_NODE
10 Node.DOCUMENT_TYPE_NODE
11 Node.DOCUMENT_FRAGMENT_NODE
12 Node.NOTATION_NODE

这12种类型中,有些节点可以包含子节点,有些没有子节点,详细如下:

常量值 节点类型 描述 子节点
1 Element 代表元素 Element, Text, Comment, ProcessingInstruction, CDATASection, EntityReference
2 Attr 代表属性 Text, EntityReference
3 Text 代表元素或属性中的文本内容。 None
4 CDATASection 代表文档中的 CDATA 部(不会由解析器解析的文本) None
5 EntityReference 代表实体引用。 Element, ProcessingInstruction, Comment, Text, CDATASection, EntityReference
6 Entity 代表实体。 Element, ProcessingInstruction, Comment, Text, CDATASection, EntityReference
7 ProcessingInstruction 代表处理指令。 None
8 Comment 代表注释。 None
9 Document 代表整个文档(DOM 树的根节点)。 Element, ProcessingInstruction, Comment, DocumentType
10 DocumentType 向为文档定义的实体提供接口 None
11 DocumentFragment 代表轻量级的 Document 对象(文档的某个部分) Element, ProcessingInstruction, Comment, Text, CDATASection, EntityReference
12 Notation 代表 DTD 中声明的符号。 None

节点类型 nodeType

每个节点都有一个 nodeType 属性,用于表明节点的类型。节点类型由在 Node 类型中定义的下列12 个数值常量来表示,任何节点类型必居其一(如上表)

if (someNode.nodeType == Node.ELEMENT_NODE){ //在 IE 中无效
 alert("元素节点");
}

上面的例子是用nodeType返回值一个node的常量名进行比较,在低版本IE无效。最好的方法是nodeType的返回值与常量值比较

if (someNode.nodeType == 1){ //适用于所有浏览器
 alert("Node is an element.");
} 

节点名:nodeName 节点值: nodeValue

要了解节点的具体信息,可以使用 nodeNamenodeValue 这两个属性。这两个属性的值完全取决于节点的类型。

nodeName属性用于返回指定节点的节点名,节点名会以大写形式返回。

if (someNode.nodeType == 1){
 value = someNode.nodeName; //nodeName 的值是元素的标签名
}

首先检查节点类型,看它是不是一个元素。如果是,则取得并保存 nodeName 的值。对于元素节点,nodeName 中保存的始终都是元素的标签名,而 nodeValue 的值则始终为 null

12种节点类型nodeValuenodeName的返回值如下表

常量值 节点类型 nodeName 返回值 nodeValue 返回值
1 Element 元素名 null
2 Attr 属性名称 属性值
3 Text #text 节点的内容
4 CDATASection #cdata-section 节点的内容
5 EntityReference 实体引用名称 null
6 Entity 实体名称 null
7 ProcessingInstruction target 节点的内容
8 Comment #comment 注释文本
9 Document #document null
10 DocumentType 文档类型名称 null
11 DocumentFragment #document 片段 null
12 Notation 符号名称 null

节点关系

文档中所有的节点之间都存在这样或那样的关系。节点间的各种关系可以用传统的家族关系来描述,相当于把文档树比喻成家谱。

childNodes

每个节点都有一个 childNodes 属性,其中保存着一个 NodeList 对象。NodeList 是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点。

NodeList 对象具有实时性,是基于 DOM 结构动态执行查询的结果,因此 DOM 结构的变化能够自动反映在 NodeList 对象中。

访问保存在 NodeList 中的节点——可以通过方括号,也可以使用 item() 方法

var firstChild = someNode.childNodes[0];
var secondChild = someNode.childNodes.item(1);
var count = someNode.childNodes.length;

parentNode

每个节点都有一个 parentNode 属性,该属性指向文档树中的父节点。包含在 childNodes 列表中的所有节点都具有相同的父节点,因此它们的parentNode 属性都指向同一个节点。

previousSibling nextSibling

包含在childNodes 列表中的每个节点相互之间都是同胞节点。通过使用列表中每个节点的 previousSiblingnextSibling 属性,可以访问同一列表中的其他节点。列表中第一个节点的 previousSibling 属性 值为 null,而列表中最后一个节点的 nextSibling 属性的值同样也为 null

if (someNode.nextSibling === null){
 alert("Last node in the parent’s childNodes list.");
} else if (someNode.previousSibling === null){
 alert("First node in the parent’s childNodes list.");
}

firstChild lastChild

父节点与其第一个和最后一个子节点之间也存在特殊关系。父节点的 firstChildlastChild 属性分别指向其 childNodes 列表中的第一个和最后一个节点。其中,someNode.firstChild 的值始终等于 someNode.childNodes[0] ,而 someNode.lastChild 的值始终等于 someNode.childNodes[someNode.childNodes.length-1]。在只有一个子节点的情况下,firstChildlastChild 指向同一个节点。如果没有子节点,那么 firstChildlastChild 的值均为 null

hasChildNodes

判断一个节点是否有子节点,这个方法在节点包含一或多个子节点的情况下返回 true;应该说,这是比查询childNodes列表的 length 属性更简单的方法。

ownerDocument

ownerDocument是所有节点都有的属性 ,该属性指向表示整个文档的文档节点(document)。这种关系表示的是任何节点都属于它所在的文档,任何节点都不能同时存在于两个或更多个文档中。通过这个属性,我们可以不必在节点层次中通过层层回溯到达顶端,而是可以直接访问文档节点。

操作节点

appendChild()

用于向 childNodes 列表的末尾添加一个节点。添加节点后,childNodes 的新增节点、父节点及以前的最后一个子节点的关系指针都会相应地得到更新。更新完成后,appendChild()返回新增的节点。

var returnedNode = someNode.appendChild(newNode);
alert(returnedNode == newNode); //true
alert(someNode.lastChild == newNode); //true 

如果传入到 appendChild()中的节点已经是文档的一部分了,那结果就是将该节点从原来的位置转移到新位置。

insertBefore()

把节点放在 childNodes 列表中某个特定的位置上,这个方法接受两个参数:要插入的节点和作为参照的节点。插入节点后,被插入的节点会变成参照节点的前一个同胞节点(previousSibling),同时被方法返回。 如果参照节点是 null,则 insertBefore()appendChild()执行相同的操作,如下面的例子所示。

//插入后成为最后一个子节点
returnedNode = someNode.insertBefore(newNode, null);
alert(newNode == someNode.lastChild); //true
//插入后成为第一个子节点
var returnedNode = someNode.insertBefore(newNode, someNode.firstChild);
alert(returnedNode == newNode); //true
alert(newNode == someNode.firstChild); //true
//插入到最后一个子节点前面
returnedNode = someNode.insertBefore(newNode, someNode.lastChild);
alert(newNode == someNode.childNodes[someNode.childNodes.length-2]); //true

replaceChild()

替换节点,replaceChild()方法接受的两个参数是:要插入的节点和要替换的节点。要替换的节点将由这个 方法返回并从文档树中被移除,同时由要插入的节点占据其位置。

//替换第一个子节点
var returnedNode = someNode.replaceChild(newNode, someNode.firstChild);
//替换最后一个子节点
returnedNode = someNode.replaceChild(newNode, someNode.lastChild);

在使用 replaceChild()插入一个节点时,该节点的所有关系指针都会从被它替换的节点复制过来。尽管从技术上讲,被替换的节点仍然还在文档中,但它在文档中已经没有了自己的位置。

removeChild()

移除节点,这个方法接受一个参数,即要移除的节点。被移除的节点将成为方法的返回值

//移除第一个子节点
var formerFirstChild = someNode.removeChild(someNode.firstChild);
//移除最后一个子节点
var formerLastChild = someNode.removeChild(someNode.lastChild);

通过 removeChild()移除的节点仍然为文档所有,只不过在文档中已经没有了自己的位置。

前面介绍的四个方法操作的都是某个节点的子节点,也就是说,要使用这几个方法必须先取得父节点(使用 parentNode 属性)。

cloneNode()

用于创建调用这个方法的节点的一个完全相同的副本。cloneNode()方法接受一个布尔值参数,表示是否执行深复制。在参数为 true的情况下,执行深复制,也就是复制节点及其整个子节点树;在参数为 false 的情况下,执行浅复制,即只复制节点本身。复制后返回的节点副本属于文档所有,但并没有为它指定父节点。除非通过 appendChild()insertBefore()replaceChild()将它添加到文档中

var deepList = myList.cloneNode(true);
alert(deepList.childNodes.length); //3(IE < 9)或 7(其他浏览器)
var shallowList = myList.cloneNode(false);
alert(shallowList.childNodes.length); //0

cloneNode()方法不会复制添加到 DOM 节点中的 JavaScript 属性,例如事件处理程序等。这个方法只复制特性、(在明确指定的情况下也复制)子节点,其他一切都不会复制。IE 在此存在一个 bug,即它会复制事件处理程序,所以我们建议在复制之前最好先移除事件处理程序。

normalize()

处理文档树中的文本节点,可能会出现文本节点不包含文本,或者接连出现两个文本节点的情况。当在某个节点上调用这个方法时,就会在该节点的后代节点中查找上述两种情况。如果找到了空文本节点,则删除它;如果找到相邻的文本节点,则将它们合并为一个文本节点。

分类栏目
© 2018邮箱:11407215#qq.comGitHub沪ICP备12039518号-6