## 9.3 DOM擴展
### 9.3.1 選擇符API
| 方法 | 描述 |
| --- | --- |
| querySelector() | 接收一個CSS選擇符,返回與該模式匹配的第一個元素,如果沒有找到匹配的元素,返回null。與getElementsById()類似,這個方法可以通過Document類型或Element類型調用。 |
| querySelectorAll() | 返回的是一個NodeList實例,而其底層實現則類似一組元素的快照,而非不斷對文檔進行搜索的動態查詢。 |
| matchesSelector() | 接收一個CSS選擇符,如果調用元素與該選擇符匹配,返回true;否則,返回false。 |
### 9.3.2 元素遍歷
Element Traversal API為DOM元素添加了以下5個屬性:
| 屬性 | 描述 |
| --- | --- |
| childElementCount | 返回子元素(不包括文本節點和注釋)的個數。|
| firstElementChild | 指向第一個子元素;firstChild的元素版。|
| lastElementChild | 指向最后一個子元素;lastChild的元素版。|
| previousElementChild | 指向前一個同輩元素;previousSibling的元素版。|
| nextElementChild | 指向后一個同輩元素;nextSibling的元素版。|
### 9.3.3 HTML5(DOM相關)
**1. 類相關擴充**
`getElementsByClassName()`:接收包含一個或多個類名的字符串,返回帶有指定類的所有與元素的NodeList。(類名不分順序)
**2. classList屬性**
HTML5新增的一種操作類名的方式,可以讓操作更簡單也更安全。classList屬性是心機和類型DOMTokenList的實例,有length屬性,可以使用item()方法,也可以使用方括號語法。
| 方法 | 描述 |
| --- | --- |
| add() | 將給定字符串值添加到類名列表中,如果已經存在就不添加了。|
| contains() | 表示列表中是否存在給定的值,如果存在則返回true,否則返回false。|
| remove() | 從列表中刪除給定的字符串。|
| toggle() | 如果列表中已經存在給定的值,刪除它;如果列表中沒有給定的值,添加它。|
**3. 焦點管理**
元素獲得焦點的方式有頁面加載、用戶輸入(通常按Tab鍵)和在代碼中調用focus()方法。HTML添加了輔助管理DOM焦點的功能。
`document.activeElement屬性`:始終會引用DOOM中當前獲得了焦點的元素。默認情況下,文檔剛加載完成時,保存的是document.body元素的引用。文檔加載期間,為null。
`document.hasFocus()方法`:用于確定文檔是否獲得了焦點。通過檢測文檔是否獲得了焦點,可以知道用戶是不是正在與頁面交互。
**4.HTMLDocument的變化**
(1)readyState屬性
兩個值:loading,正在加載文檔;complete,已經加載完文檔。
可以通過readyState屬性來實現一個指示文檔已經加載完成的指示器。
(2)兼容模式
compatMode區分渲染頁面的模式是標準的還是混雜的。
兩個值:標準模式,CSS1Compat;混雜模式,BackCompat
(3)head屬性
HTML5新增了document.head屬性
引用文檔的`<head>`元素:
~~~
var head = document.head || document.getElementsByTagName("head")[0];
~~~
**5. 字符集屬性**
HTML5新增了幾個與文檔字符集有關的屬性。
|屬性|描述|
|---|---|
| charset | 表示文檔中實際使用的字符集,也可以用來指定新字符集。默認“UTF-16”,可以通過<meta>元素、響應頭部或直接設置charset屬性修改這個值。|
| defaultCharset |表示根據默認瀏覽器及操作系統的設置,當前文檔默認的字符集。|
通過這兩個屬性可以得到文檔使用的字符編碼的具體信息,也能對字符編碼進行準確地控制。(無默認的字符集,兩者不一樣。)
**6. 自定義數據屬性**
HTML5規定可以為元素添加非標準的屬性,但要添加前綴data-,目的是為元素提供與渲染無關的信息或提供語義信息。
添加自定義屬性之后,可以通過元素的**dataset屬性**來訪問自定義屬性的值。dataset屬性的值是DOMStringMap的一個實例,即一個名值對兒的映射。
~~~
<div id="myDiv" data-appId="12345" data-myname="Nicholas"></div>
var div = document.getElementById("myDiv");
//取得自定義屬性的值
var appId = div.dataset.appId;
var myName = div.dataset.myname;
//設置值
div.dataset.appId = 23456;
div.dataset.myname = "Michael";
if (div.dataset.myname){
alert("Hello, " + div.dataset.myname);
}
~~~
**7.插入標記**
為了簡化給文檔插入大量新HTML標記的情況,HTML5規范了與插入標記相關的DOM擴展。
(1)innerHTML屬性
在讀模式下,innerHTML 屬性返回與調用元素的所有子節點(包括元素、注釋和文本節點)對應的HTML 標記。
在寫模式下,innerHTML 會根據指定的值創建新的DOM樹,然后用這個DOM樹完全替換調用元素原先的所有子節點。
讀取Element的 innerHTML 屬性作為字符串標記返回那個元素的內容。
~~~
<div id="div"><p>123</p></div>
var d = document.getElementById('div');
d.innerHTML // "<p>123</p>"
~~~
除了獲取,還可以設置
~~~
d.innerHTML = '<span>99</span>'
// <div id="div"><span>99</span></div>
~~~
大多數瀏覽器中,通過innerHTML插入`<script>`并不會執行其中的腳本。
(2)outerHTML屬性
在讀模式下,outerHTML返回調用它的元素及所有子節點的HTML標簽。
在寫模式下,outerHTML會根據指定的HTML字符串創建新的DOM子樹,然后用這個DOM子樹完全替換調用元素。
~~~
d.outerHTML
// "<div id="div"><p>123</p></div>"
~~~
注意:只有Element節點有outerHTML屬性,Document節點沒有。
(3)insertAdjacentHTML()方法
將任意的HTML標記字符插入到指定的元素“相鄰”的位置。
接收兩個參數:插入位置和要插入的HTML文本。
第一個參數必須是:“beforebegin”、“afterbegin”、“beforeend”和“afterend”之一。
如下圖:

第二個參數是一個HTML字符串。(與innerHTML和outerHTML的值相同)
(4)內存與性能問題
使用本節介紹的方法替換子節點可能會導致瀏覽器的內存占用問題,尤其是在IE 中,問題更加明顯。在**刪除帶有事件處理程序或引用了其他JavaScript 對象子樹時,就有可能導致內存占用問題。**假設某個元素有一個事件處理程序(或者引用了一個JavaScript 對象作為屬性),在使用前述某個屬性將該元素從文檔樹中刪除后,元素與事件處理程序(或JavaScript 對象)之間的綁定關系在內存中并沒有一并刪除。如果這種情況頻繁出現,頁面占用的內存數量就會明顯增加。因此,在使用innerHTML、outerHTML 屬性方法時,**最好先手工刪除要被替換的元素的所有事件處理程序和JavaScript 對象屬性。**
**8. scrollIntoView()方法**
srollIntoView()方法可以在所有HTML元素上調用,通過滾動瀏覽器窗口或某個容器元素,調用元素就可以出現在視口當中。如果給這個方法傳入true作為參數,或者不傳入任何參數,那么窗口滾動之后會讓調用的元素的頂部與視口頂部盡可能平齊。如果傳入false作為參數,調用元素會盡可能全部出現在視口當中,(可能的話,調用元素的底部會與是視口底部平齊)不過頂部不一定平齊。
~~~
//讓元素可見
document.forms[0].scrollIntoView();
~~~
當頁面發生變化時,一般會用這個方法來吸引用戶的注意力。實際上,為某個元素設置焦點也會導致瀏覽器滾動并顯示出獲得焦點的元素。
### 9.3.4 專有擴展
**1. 文檔模式**
**2. children屬性**
由于IE9之前的版本與其他瀏覽器在處理文本節點中的空白符時有差異,因此出現了children屬性。
這個屬性是HTMLCollection的實例,**只包含元素中同樣還是元素的子節點**。除此之外,children屬性與childNodes沒有什么區別。
**3. contains()方法**
contains()方法:祖先節點即搜索開始的節點調用,接受一個參數,即檢測的后代節點。如果被檢測的節點是后代節點,返回true,否則返回false。
**4. 滾動**
- 前言
- 第一章 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 原生函數