[TOC]
## 9.1 节点层次
DOM可以将任何HTML文档描绘成一个由**多层节点**构成的结构。节点分为不同的类型,拥有个自己的特点、数据和方法,表示不同的信息及(或)标记。
节点之间的关系构成了层次,而所有页面标记则表现为一个以特定节点为根节点的**树形结构**。
例如:![](https://box.kancloud.cn/0af8d7484f4f056b2573203f026a3444_486x266.png)
### 9.1.1 Node类型
DOM1级定义了一个`Node`接口,该接口将由DOM中的所有节点类型实现。这个Node接口在JavaScript中是作为Node类型实现的。除了IE之外,在其他所有浏览器中都可以访问到这个类型。**JavaScript中的所有节点类型都继承自Node类型**,因此所有节点类型都**共享着相同的基本属性和方法**。
**了解节点的具体信息,可以使用`nodeName和nodeValue`属性**
|||
|---|---|
|元素节点 | Node.ELEMENT_NODE(1)|
|属性节点 | Node.ATTRIBUTE_NODE(2)|
|文本节点 | Node.TEXT_NODE(3)|
|CDATA节点 | Node.CDATA_SECTION_NODE(4)|
|实体引用名称节点 | Node.ENTRY_REFERENCE_NODE(5)|
|实体名称节点 | Node.ENTITY_NODE(6)|
|处理指令节点 | Node.PROCESSING_INSTRUCTION_NODE(7)|
|注释节点 | Node.COMMENT_NODE(8)|
|文档节点 | Node.DOCUMENT_NODE(9)|
|文档类型节点 | Node.DOCUMENT_TYPE_NODE(10)|
|文档片段节点 | Node.DOCUMENT_FRAGMENT_NODE(11)|
|DTD声明节点 | Node.NOTATION_NODE(12)|
**1.节点关系**
节点树中的节点彼此拥有**层级**关系。
父(parent)、子(child)和同胞(sibling)等术语用于描述这些关系。父节点拥有子节点。同级的子节点被称为同胞(兄弟或姐妹)。
* 在节点树中,顶端节点被称为根(root)
* 每个节点都有父节点、除了根(它没有父节点)
* 一个节点可拥有任意数量的子节点
* 同胞是拥有相同父节点的节点
![](https://box.kancloud.cn/650369666614cdf7ee1880b6bfd4ab85_801x421.png)
每个节点都有一个`childNodes`属性,其中保存着一个`NodeList`对象。NodeList是一种类数组对象,用于保存一组有序的节点,可以通过位置来访问这些节点。
**访问保存在NodeList中的节点**
~~~
var firstChild = someNode.childNodes[0];
var secondChild = someNode.childNodes.item(1);
var count = someNode.childNodes.length;
~~~
* `childNodes`属性访问更方便;
* `hasChildNodes()`在节点包含一或多个子节点的情况下返回true,比查询childNodes列表的length属性更简单;
* 所有节点都有一个`ownerDocument`属性,指向表示整个文档的文档节点。这种关系表示的是任何节点都属于它所在的文档,任何节点都不能同事存在于两个或更多个文档中。
**2.操作节点**
|||
|---|---|
| appendChild(newNode) | 向childNodes列表的末尾添加一个节点,返回新增的节点|
| insertBefore(newNode , referNode) | 向childNodes列表特定位置添加一个节点,返回新增的节点 |
| replaceChild(newNode,repNode) | 替换childNodes列表中的某个节点,返回替换新节点 |
| removeChild(node)| 移除节点,返回被移除的点|
以上方法操作的都是某个节点的子节点,必须先取得父节点,然而并不是所有类型的节点都有子节点,不支持子节点的节点上调用会导致错误。
**3.其他方法**
|||
|---|---|
| cloneNode() | 创建调用这个方法的节点的一个完全相同的副本,接受一个boolean参数,表示是否执行深复制(复制节点及其子节点树)。复制后返回的节点副本属于文档所有,没有父节点。|
| insertBefore(newNode , referNode) | 向childNodes列表特定位置添加一个节点,返回新增的节点 |
| normalize() | 移除空的文本节点,并合并相邻的文本节点。
### 9.1.2 Document类型
JavaScript通过**Document类型**表示文档。在浏览器中,document对象是HTMLDocument的一个实例,表示整个HTML页面。
document对象是window对象的一个属性,因此可以将其作为全局对象来访问。
Document节点特征:
* nodeType的值为9;
* nodeName的值为"#document";
* nodeValue的值为null;
* parentNode的值为null;
* ownerDocument的值为null;
* 其子节点DocumentType(最多一个)、Element(最多一个)、 ProcessingInstruction Comment
**Document类型可以表示HTML页面,但更常作为HTMLDocument实例的document对象,取得与页面有关的信息,操作页面外观及其底层结构。**
**1.文档的子节点**
| 属性 | 描述 |
| --- | --- |
| documentElement | 始终指向HTML页面中的`<html>`属性 。 |
| body | 直接指向`<body>`元素。 |
|doctype | 指向子节点DocumentType 。|
**2.文档信息**
作为HTMLDocument的一个实例,document对象还有一些属性,表示网页的一些信息。
| 属性 | 描述 |
| --- | --- |
| title |包含<title>元素中的文本 |
| URL | 包含页面完整的URL(地址栏中显示的地址) |
| domain | 只包含页面的域名 |
| referrer | 包含链接到当前页面的那个页面的URL,无来源则为空字符串 |
**3.查找元素**
| 方法 | 描述 |
| --- | --- |
| getElementById(id) | 找到与id匹配(大小写)的元素并返回。*同名返回第一个* |
| getElementsByTagName(tag) | 取得元素的标签名,返回包含零或多个元素的NodeList。HTML文档中,返回一个HTMLCollection对象(动态的集合)。可以通过namedItem(name)取得集合中name特性的项。 |
| getElementsByName(name) | 返回带有给定name特性的所有元素。 |
**4.特殊集合**
document对象还有一些特殊的集合,都是HTMLCollection对象。
| 对象集合| | 描述 |
| --- | --- |
| anchors | 返回文档中所有带name特性的`<a>`元素。|
| forms | 返回文档中所有的`<form>`元素。|
| images | 返回文档中所有的`<img>`元素。|
| links | 返回文档中所有带href特性的`<a>`元素。|
**5.文档写入**
| 方法| | 描述 |
| --- | --- |
| write(str) | 向文档写入文本。|
| writeln(str)| 写入文本后添加`\n`换行符。|
| open() | 打开一个流,以收集来自任何` document.write()` 或 `document.writeln()` 方法的输出。|
| close() | 关闭用 `document.open() `方法打开的输出流,并显示选定的数据。|
**6. 文档元素属性**
所有文档元素都有下面的属性:
* clientWidth、clientHeight
clientHeight 属性返回元素节点可见部分的高度, clientWidth属性返回元素节点可见部分的宽度。
所谓“可见部分”,指的是不包括溢出(overflow)的大小,只返回该元素在容器中占据的大小,对于有滚动条的元素来说,它们等于滚动条围起来的区域大小。
这两个属性的值不包括滚动条、边框和Margin,只包含内容和它的内边距,单位为像素。
对于整张网页来说,当前可见高度(即视口高度)要从document.documentElement对象上获取,等同于window.innerHeight属性减去水平滚动条的高度。
没有滚动条时,这两个值是相等的;有滚动条时,前者小于后者。
~~~
var rootElement = document.documentElement; // 没有水平滚动条时
rootElement.clientHeight === window.innerHeight // true // 没有垂直滚动条时
rootElement.clientWidth === window.innerWidth // true
~~~
对于`<i>、<code>和<span>`这些内联元素,clientWidth和clientHeight总是0
* clientLeft、clientTop
clientLeft 属性等于元素节点左边框(left border)的宽度, clientTop属性等于网页元素顶部边框的宽度,单位为像素。
但是如果元素有滚动条,并且浏览器将这些滚动条放置在左侧或顶部(极少见),这两个属性就包括了滚动条的宽度,但不包括Margin和Padding。
如果元素是内联元素,clientLeft和clientTop属性总是为0。
* scrollWidth、scrollHeight
scrollHeight属性返回某个网页元素的总高度, scrollWidth 属性返回总宽度,也就是元素的内容加上它的内边距再加上任何溢出内容的尺寸。这两个属性是只读属性。
它们返回的是整个元素的高度或宽度,包括由于存在滚动条而不可见的部分。默认情况下,它们包括Padding,但不包括Border和Margin。
* scrollLeft、scrollTop
scrollLeft属性表示网页元素的水平滚动条向右侧滚动的像素数量, scrollTop 属性表示网页元素的垂直滚动条向下滚动的像素数量。对于那些没有滚动条的网页元素,这两个属性总是等于0。
如果要查看整张网页的水平的和垂直的滚动距离,要从document.body元素上读取。
document.body.scrollLeft
document.body.scrollTop
这两个属性都可读写,设置该属性的值,会导致浏览器将指定元素自动滚动到相应的位置。
* offsetWidth、offsetHeight
offsetHeight 属性返回元素的垂直高度,offsetWidth 属性返回水平宽度。这两个属性值包括Padding和Border、以及滚动条,也就是说从边框的左上角开始计算,这也意味着,offsetHeight只比clientHeight少了边框的高度。它们的单位为像素,都是只读。 整张网页的高度,可以在document.documentElement和document.body上读取。
// 网页总高度
document.documentElement.offsetHeight
document.body.offsetHeight
// 网页总宽度
document.documentElement.offsetWidth
document.body.offsetWidth
* offsetLeft、offsetTop
offsetLeft 返回当前元素左上角相对于 offsetParent节点的垂直偏移, offsetTop 返回水平位移,单位为像素。通常,这两个值是指相对于父节点的位移。
### 9.1.3 Element类型
Element类型用于表现XML或HTML元素,提供了**对元素标签名、子节点及特性的访问**。
**Element节点特征:**
* nodeType的值为1;
* nodeName的值为元素的标签名;
* nodeValue的值为null;
* parentNode可能是Document或Element;
* 其子节点可能是Element、Tex、Comment、ProcessingInstruction、CDATASection或EntityReference。
可以使用nodeName属性或tagName属性访问元素的标签名。
在HTML中,标签名始终都以全部大写表示,推荐:`element.tagName.toLowerCase() //获取标签`
**1.HTML元素**
所有HTML元素都由HTMLElement类型或它的子类型来表示。HTMLElement类型直接继承自Element并添加了一些属性,分别对应于每个HTML元素中都存在的标准特性。
| 特性 | 描述 |
| --- | --- |
| id | 元素在文档中的唯一标识符。|
| title| 有关元素的附加标题说明信息。|
| lang | 元素内容的语言。|
| dir | 语言的方向。(ltr为从左到右)|
| className | 与元素的class特性对应,为元素指定的CSS类。|
**2.取得特性**
每个元素都有一或多个特性,这些特性的用途是给出相应元素或其内容的附加信息。
`getAttribute(attr)`:返回指定特性的值。给定特性不存在则返回null,还可以获取自定义特性的值(html5规范自定义特性加上data-前缀以便验证)
任何元素的所有**公认(非自定义的)特性**都可以通过**DOM元素**本身的属性来访问。
有两类特殊的特性,虽然有对应的属性名,但属性的值与通过`getAttribute(attr)`返回的值并不相同:
* style:get返回CSS文本;属性访问返回一个对象。
* onclick:get返回相应代码的字符串;属性访问返回一个JavaScript函数(未指定返回null)。
**3.设置特性**
setAttribute(attr,attrValue):替换现在指定特性的值,若不存在,则创建改属性并设置相应的值。
通过setAttribute()方法既可以操作HTML特性也可以操作自定义特性。设置的特性名会被统一转换为小写形式。
注意:为DOM元素添加自定义的属性,该属性不会自动成为元素的特性。
~~~
div.mycolor = "red",
aler(div.getAttribute("mycolor")); //null
~~~
removeAttribute(attr):彻底删除元素的特性,不仅特性的值,还包括特性本身。
**4.attributes属性**
Element类型是使用attributes属性的**唯一**一个DOM节点类型。attributes属性中包含一个`NamedNodeMap`,是一个动态的集合。
元素的每一个属性都由一个**Attr节点**表示,每个节点都保存在`NamedNodeMap对象`中。
NamedNodeMap对象方法
| 方法 | 描述 |
| --- | --- |
| getNamedItem(name) | 返回nodeName属性等于name 的节点。|
| removeNameItem(name) | 从列表中移除nodeName属性等于name的节点。|
| setNamedItem(node) | 向列表中添加节点,以节点的nodeName属性为索引。|
| item(pos) | 返回位于数字pos位置处的节点。|
attributes属性中包含一系列节点,每个节点的nodeName就是特性名称,而节点的nodeValue就是特性的值。
**5.创建元素**
`document.createElement()`方法可以创建新元素。这个方法值接受一个参数,即要创建元素的标签名(HTML不区分大小写)。
使用createElement()方法创建新元素的同时,也为新元素设置了ownerDocument属性,此时还可以操作元素的特性,为它添加更多子节点,以及执行其他操作。
需要使用节点操作方法把新元素添加到文档树中,浏览器才会呈现改元素。
**6.元素的子节点**
元素可以有任意数目的子节点和后代节点。元素的childeNodes属性中包含了它的`所有子节点`,这些子节点有可能是元素、文本节点、注释或处理指令。
不同节点看待节点层次会有所不同。
元素也支持getElementsByTagName()方法,搜索起点是当前元素,只返回当前元素的直接后代元素。
### 9.1.4 Text类型
文本节点有Text类型表示,包含的是可以照字面解释的**纯文本内容**(可以包含转义后的HTML字符,但不包含代码)。
Text节点特征:
* nodeType的值为3;
* nodeName的值为“#text";
* nodeValue的值为节点所包含的文本;
* parentNode是一个Element;
* 不支持(没有)子节点。
可以通过nodeValue属性或data属性访问Text节点中包含的文本。
length属性:保存着节点中字符的数目。
操作文本的方法:
| 方法 | 描述 |
| --- | --- |
| 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为止处的字符串。 |
获取文本节点的引用后,如果文本节点存在于文档树中,修改节点的结果会立即反映,修改后字符串会经过HTML编码(如符号会被转义)。
**1.创建文本节点**
document.createTextNode(text):创建文本节点,文本会按照HTML格式编码。
~~~
var element = document.createElement("div");
element.className = "message";
var textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
document.body.appendChild(element);
~~~
**2.规范化文本节点**
DOM文档中存在相邻的同胞文本节点容易导致混乱,使用由`Node类型定义的normalize()方法`可以将所有文本节点合并成一个节点。
### 9.1.5 Comment类型
注释在DOM中是通过Comment类型来表示的。
Comment节点特征:
* nodeType的值为8;
* nodeName的值为“#comment";
* nodeValue的值为注释的内容;
* parentNode可能是Document或Element;
* 不支持(没有)子节点。
Comment类型与Text类型继承自相同的鸡肋,拥有出splitText()之外的所有字符串操作方法。
### 9.1.6 Attr类型
元素的特性在DOM中以Attr类型来表示。从技术角度,特性就是存在于元素的attributes属性中的节点。
Attr类型特征:
* nodeType的值为2;
* nodeName的值为特性的名称;
* nodeValue的值为特性的值;
* parentNode为null;
* HTML中不支持(没有)子节点。
Attr对象有3个属性:name、value和specified。name是特性名称,value是特性的值,specified是一个布尔值,用以区别特性是在代码中指定的,还是默认的。
`document.createAttribute()方法`可以创建新的特性节点。
~~~
var attr = document.createAttribute("align");
attr.value = "left";
element.setAttributeNode(attr);
alert(element.attribute["align"].value); //"left"
alert(element.attributeNode("align").value); //"left"
~~~
- 前言
- 第一章 JavaScript简介
- 第三章 基本概念
- 3.1-3.3 语法、关键字和变量
- 3.4 数据类型
- 3.5-3.6 操作符、流控制语句(暂略)
- 3.7函数
- 第四章 变量的值、作用域与内存问题
- 第五章 引用类型
- 5.1 Object类型
- 5.2 Array类型
- 5.3 Date类型
- 5.4 基本包装类型
- 5.5 单体内置对象
- 第六章 面向对象的程序设计
- 6.1 理解对象
- 6.2 创建对象
- 6.3 继承
- 第七章 函数
- 7.1 函数概述
- 7.2 闭包
- 7.3 私有变量
- 第八章 BOM
- 8.1 window对象
- 8.2 location对象
- 8.3 navigator、screen与history对象
- 第九章 DOM
- 9.1 节点层次
- 9.2 DOM操作技术
- 9.3 DOM扩展
- 9.4 DOM2和DOM3
- 第十章 事件
- 10.1 事件流
- 10.2 事件处理程序
- 10.3 事件对象
- 10.4 事件类型
- 第十一章 JSON
- 11.1-11.2 语法与序列化选项
- 第十二章 正则表达式
- 12.1 创建正则表达式
- 12.2-12.3 模式匹配与RegExp对象
- 第十三章 Ajax
- 13.1 XMLHttpRequest对象
- 你不知道的JavaScript
- 一、作用域与闭包
- 1.1 作用域
- 1.2 词法作用域
- 1.3 函数作用域与块作用域
- 1.4 提升
- 1.5 作用域闭包
- 二、this与对象原型
- 2.1 关于this
- 2.2 全面解析this
- 2.3 对象
- 2.4 混合对象“类”
- 2.5 原型
- 2.6 行为委托
- 三、类型与语法
- 3.1 类型
- 3.2 值
- 3.3 原生函数