[TOC]
## 9.1 節點層次
DOM可以將任何HTML文檔描繪成一個由**多層節點**構成的結構。節點分為不同的類型,擁有個自己的特點、數據和方法,表示不同的信息及(或)標記。
節點之間的關系構成了層次,而所有頁面標記則表現為一個以特定節點為根節點的**樹形結構**。
例如:
### 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)
* 每個節點都有父節點、除了根(它沒有父節點)
* 一個節點可擁有任意數量的子節點
* 同胞是擁有相同父節點的節點

每個節點都有一個`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 原生函數