一、節點層次
DOM
是針對 HTML
和 XML
文檔的一個API
(應用程序編程接口)。DOM
描繪了一個層次化的節點樹,允許開發人員添加、移除和修改頁面的某一部分。
DOM文檔對象模型
DOM
可以將任何 HTML
或 XML
文檔描繪成一個由多層節點構成的結構。節點分為幾種不同的類型,每種類型分別表示文檔中不同的信息及(或)標記。每個節點都擁有各自的特點、數據和方法,另外也與其他節點存在某種關系。節點之間的關系構成了層次,而所有頁面標記則表現為一個以特定節點為根節點的樹形結構。
文檔元素是文檔的最外層元素,文檔中的其他所有元素都包含在文檔元素中。每個文檔只能有一個文檔元素。在 HTML 頁面中,文檔元素始終都是 <html> 元素。在 XML 中,沒有預定義的元素,因此任何元素都可能成為文檔元素。
每一段標記都可以通過樹中的一個節點來表示:HTML
元素通過元素節點表示,特性(attribute)
通過特性節點表示,文檔類型通過文檔類型節點表示,而注釋則通過注釋節點表示。總共有 12 種節點類型,這些類型都繼承自一個基類型。
1、Node類型
DOM1 級定義了一個 Node 接口,該接口將由 DOM 中的所有節點類型實現。這個 Node 接口在JavaScript 中是作為 Node 類型實現的;除了 IE 之外,在其他所有瀏覽器中都可以訪問到這個類型。JavaScript 中的所有節點類型都繼承自 Node 類型,因此所有節點類型都共享著相同的基本屬性和方法。每個節點都有一個 nodeType 屬性,用于表明節點的類型。
(1) nodeName 和 nodeValue 屬性
要了解節點的具體信息,可以使用 nodeName 和 nodeValue 這兩個屬性。這兩個屬性的值完全取決于節點的類型。
(2)節點關系
文檔中所有的節點之間都存在相互關系。
每個節點都有一個 childNodes 屬性,其中保存著一個 NodeList 對象。 NodeList 是一種類數組對象,用于保存一組有序的節點,可以通過位置來訪問這些節點。請注意,雖然可以通過方括號語法來訪問 NodeList 的值,而且這個對象也有 length 屬性,但它并不是 Array 的實例。 NodeList 對象的獨特之處在于,它實際上是基于 DOM 結構動態執行查詢的結果,因此 DOM 結構的變化能夠自動反映在 NodeList 對象中。
var firstChild = someNode.childNodes[0];
var secondChild = someNode.childNodes.item(1);
var count = someNode.childNodes.length;
每個節點都有一個 parentNode 屬性,該屬性指向文檔樹中的父節點。包含在 childNodes 列表中的所有節點都具有相同的父節點,因此它們的 parentNode 屬性都指向同一個節點。
包含在childNodes 列表中的每個節點相互之間都是同胞節點。通過使用列表中每個節點的 previousSibling和 nextSibling 屬性,可以訪問同一列表中的其他節點。列表中第一個節點的 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.");
}
所有節點都有的最后一個屬性是 ownerDocument ,該屬性指向表示整個文檔的文檔節點。這種關系表示的是任何節點都屬于它所在的文檔,任何節點都不能同時存在于兩個或更多個文檔中。通過這個屬性,我們可以不必在節點層次中通過層層回溯到達頂端,而是可以直接訪問文檔節點。
(3)操作節點
因為關系指針都是只讀的,所以 DOM 提供了一些操作節點的方法。其中,最常用的方法是appendChild() ,用于向 childNodes 列表的末尾添加一個節點。
使用insertBefore() 方法可以把節點放在 childNodes 列表中某個特定的位置上,接受兩個參數:要插入的節點和作為參照的節點。
2、Document類型
在瀏覽器中, document 對象是 HTMLDocument (繼承自 Document 類型)的一個實例,表示整個 HTML 頁面。
Document 類型可以表示 HTML 頁面或者其他基于 XML 的文檔。不過,最常見的應用還是作為HTMLDocument 實例的 document 對象。通過這個文檔對象,不僅可以取得與頁面有關的信息,而且還能操作頁面的外觀及其底層結構。
(1)文檔的子節點
documentElement屬性,該屬性始終指向 HTML 頁面中的 <html> 元素。作為 HTMLDocument 的實例, document 對象還有一個 body 屬性,直接指向 <body> 元素。
var body = document.body; //取得對<body>的引用
所有瀏覽器都支持 document.documentElement 和 document.body 屬性。
(2)文檔信息
<title> 元素中的文本——顯示在瀏覽器窗口的標題欄或標簽頁上。修改 title 屬性的值不會改變 <title>元素。
//取得文檔標題
var originalTitle = document.title;
//設置文檔標題
document.title = "New page title";
對網頁的請求有關的屬性:URL 、 domain 和 referrer 。
- URL 屬性中包含頁面完整的 URL(即地址欄中顯示的 URL);
- domain 屬性中只包含頁面的域名;
- referrer屬性中保存著鏈接到當前頁面的URL;
//取得完整的 URL
var url = document.URL;
//取得域名
var domain = document.domain;
//取得來源頁面的 URL
var referrer = document.referrer;
(3)查找元素
Document 類型為此提供了兩個方法: getElementById() 和 getElementsByTagName() 。
getElementById() ,接收一個參數:要取得的元素的 ID。如果找到相應的元素則返回該元素,如果不存在帶有相應 ID 的元素,則返回 null 。如果頁面中多個元素的 ID 值相同, getElementById() 只返回文檔中第一次出現的元素。
<div id="myDiv">Some text</div>
var div = document.getElementById("myDiv"); //取得<div>元素的引用
getElementsByTagName(), 接收一個參數:要取得元素的標簽名。返回的是包含零或多個元素的 NodeList 。
var images = document.getElementsByTagName("img");
alert(images.length); //輸出圖像的數量
alert(images[0].src); //輸出第一個圖像元素的 src 特性
alert(images.item(0).src); //輸出第一個圖像元素的 src 特性
可以使用方括號語法或 item() 方法來訪問 HTMLCollection 對象中的項。
HTMLCollection 對象還有一個方法,叫做 namedItem() ,使用這個方法可以通過元素的 name特性取得集合中的項。
<img src="myimage.gif" name="myImage">
var myImage = images.namedItem("myImage");
var myImage = images["myImage"]; //對命名的項也可以使用方括號語法來訪問
getElementsByName() ,返回帶有給定 name 特性的所有元素。最常使用 getElementsByName() 方法的情況是取得單選按鈕;為了確保發送給瀏覽器的值正確無誤,所有單選按鈕必須具有相同的 name 特性。
<fieldset>
<legend>Which color do you prefer?</legend>
<ul>
<li>
<input type="radio" value="red" name="color" id="colorRed">
<label for="colorRed">Red</label>
</li>
<li>
<input type="radio" value="green" name="color" id="colorGreen">
<label for="colorGreen">Green</label>
</li>
<li>
<input type="radio" value="blue" name="color" id="colorBlue">
<label for="colorBlue">Blue</label>
</li>
</ul>
</fieldset>
var radios = document.getElementsByName("color");
3、Element類型
Element 類型用于表現 XML或 HTML元素,提供了對元素標簽名、子節點及特性的訪問。
要訪問元素的標簽名,可以使用 nodeName 屬性,也可以使用 tagName 屬性;這兩個屬性會返回相同的值(使用后者主要是為了清晰起見)。
<div id="myDiv"></div>
var div = document.getElementById("myDiv");
alert(div.tagName); //"DIV"
alert(div.tagName == div.nodeName); //true
在 HTML 中,標簽名始終都以全部大寫表示;
(1) HTML 元素
所有 HTML 元素都由 HTMLElement 類型表示或它的子類型來表示。 HTMLElement 類型直接繼承自 Element 并添加了一些屬性。
<div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div>
var div = document.getElementById("myDiv");
//獲取每個屬性的值
alert(div.id); //"myDiv""
alert(div.className); //"bd"
alert(div.title); //"Body text"
alert(div.lang); //"en"
alert(div.dir); //"ltr"
//為每個屬性賦予新的值
div.id = "someOtherId";
div.className = "ft";
div.title = "Some other text";
div.lang = "fr";
div.dir ="rtl";
(2)取得特性
每個元素都有一或多個特性,這些特性的用途是給出相應元素或其內容的附加信息。操作特性的DOM 方法主要有三個,分別是 getAttribute() 、 setAttribute() 和 removeAttribute() 。這三個方法可以針對任何特性使用,包括那些以 HTMLElement 類型屬性的形式定義的特性。
var div = document.getElementById("myDiv");
alert(div.getAttribute("id")); //"myDiv"
alert(div.getAttribute("class")); //"bd"
alert(div.getAttribute("title")); //"Body text"
alert(div.getAttribute("lang")); //"en"
alert(div.getAttribute("dir")); //"ltr"
如果給定名稱的特性不存在, getAttribute() 返回 null 。
通過 getAttribute() 方法也可以取得自定義特性。
<div id="myDiv" my_special_attribute="hello!"></div>
//包含一個名為 my_special_attribute 的自定義特性,它的值是 "hello!"
var value = div.getAttribute("my_special_attribute");
特性的名稱是不區分大小寫的,即 "ID" 和 "id" 代表的都是同一個特性。
根據 HTML5 規范,自定義特性應該加上 data- 前綴以便驗證。
(3)設置特性
setAttribute() 會以指定的值替換現有的值;如果特性不存在,setAttribute()則創建該屬性并設置相應的值。
div.setAttribute("id", "someOtherId");
div.setAttribute("class", "ft");
div.setAttribute("title", "Some other text");
div.setAttribute("lang","fr");
div.setAttribute("dir", "rtl");
通過 setAttribute() 方法既可以操作 HTML 特性也可以操作自定義特性。通過這個方法設置的特性名會被統一轉換為小寫形式,即 "ID" 最終會變成 "id" 。
因為所有特性都是屬性,所以直接給屬性賦值可以設置特性的值。為 DOM 元素添加一個自定義的屬性,該屬性不會自動成為元素的特性。
div.id = "someOtherId";
div.align = "left";
div.mycolor = "red";
alert(div.getAttribute("mycolor")); //null(IE 除外)
removeAttribute()用于徹底刪除元素的特性。調用這個方法不僅會清除特性的值,而且也會從元素中完全刪除特性。
div.removeAttribute("class");
(4) attributes 屬性
Element 類型是使用 attributes 屬性的唯一一個 DOM節點類型。 attributes 屬性中包含一個NamedNodeMap ,與 NodeList 類似,也是一個“動態”的集合。元素的每一個特性都由一個 Attr 節點表示,每個節點都保存在 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;
也可以使用這種語法來設置特性的值,即先取得特性節點,然后再將其 nodeValue 設置為新值。
//設置特性的值
element.attributes["id"].nodeValue = "someOtherId";
//刪除具有給定名稱的特性
var oldAttr = element.attributes.removeNamedItem("id");
//為元素添加一個新特性
element.attributes.setNamedItem(newAttr);
(5)創建元素
使用 document.createElement() 方法可以創建新元素。
var div = document.createElement("div");
//操作元素的特性,為它添加更多子節點
div.id = "myNewDiv";
div.className = "box";
//把新元素添加到文檔樹
document.body.appendChild(div);
//以另一種方式使用 createElement()
var div = document.createElement("<div id=\"myNewDiv\" class=\"box\"></div >");
在新元素上設置這些特性只是給它們賦予了相應的信息。由于新元素尚未被添加到文檔樹中,因此設置這些特性不會影響瀏覽器的顯示。要把新元素添加到文檔樹,可以使用 appendChild() 、 insertBefore() 或replaceChild() 方法。
(6)元素的子節點
元素可以有任意數目的子節點和后代節點,因為元素可以是其他元素的子節點。元素的childNodes 屬性中包含了它的所有子節點,這些子節點有可能是元素、文本節點、注釋或處理指令。
4、Text類型
文本節點由 Text 類型表示,包含的是可以照字面解釋的純文本內容。純文本中可以包含轉義后的HTML 字符,但不能包含 HTML 代碼。
(1)創建文本節點
可以使用 document.createTextNode() 創建新文本節點,這個方法接受一個參數——要插入節點中的文本。
var element = document.createElement("div");
element.className = "message";
var textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
document.body.appendChild(element);
(2)規范化文本節點
normalize()將相鄰文本節點合并的方法。這個方法是由 Node 類型定義的(因而在所有節點類型中都存在)。
var element = document.createElement("div");
element.className = "message";
var textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
var anotherTextNode = document.createTextNode("Yippee!");
element.appendChild(anotherTextNode);
document.body.appendChild(element);
alert(element.childNodes.length); //2
element.normalize();
alert(element.childNodes.length); //1
alert(element.firstChild.nodeValue); // "Hello world!Yippee!"
(3)分割文本節點
splitText() 將一個文本節點分成兩個文本節點。
原來的文本節點將包含從開始到指定位置之前的內容,新文本節點將包含剩下的文本。這個方法會返回一個新文本節點,該節點與原節點的parentNode 相同。
var element = document.createElement("div");
element.className = "message";
var textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
document.body.appendChild(element);
var newNode = element.firstChild.splitText(5);
alert(element.firstChild.nodeValue); //"Hello"
alert(newNode.nodeValue); //" world!"
alert(element.childNodes.length); //2
分割文本節點是從文本節點中提取數據的一種常用 DOM解析技術。
5、Comment類型
注釋在 DOM 中是通過 Comment 類型來表示的。
Comment 類型與 Text 類型繼承自相同的基類,因此它擁有除 splitText() 之外的所有字符串操作方法。
6、CDATASection類型
CDATASection 類型只針對基于 XML 的文檔,表示的是 CDATA 區域。與 Comment 類似,CDATASection 類型繼承自 Text 類型,因此擁有除splitText() 之外的所有字符串操作方法。
二、DOM操作技術
1、動態腳本
創建動態腳本也有兩種方式:插入外部文件和直接插入 JavaScript 代碼。
//動態加載的外部 JavaScript 文件
<script type="text/javascript" src="client.js"></script>
//創建節點的 DOM 代碼
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "client.js";
document.body.appendChild(script);
//使用函數來封裝
function loadScript(url){
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
document.body.appendChild(script);
}
//調用
loadScript("client.js");
2、動態樣式
能夠把 CSS 樣式包含到 HTML 頁面中的元素有兩個。其中, <link> 元素用于包含來自外部的文件,而 <style> 元素用于指定嵌入的樣式。
所謂動態樣式是指在頁面剛加載時不存在的樣式;動態樣式是在頁面加載完成后動態添加到頁面中的。
//引用
<link rel="stylesheet" type="text/css" href="styles.css">
//動態創建
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = "style.css";
var head = document.getElementsByTagName("head")[0];
head.appendChild(link);
//函數的形式
function loadStyles(url) {
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = url;
var head = document.getElementsByTagName("head")[0];
head.appendChild(link);
}
loadStyles("styles.css");
必須將 <link> 元素添加到 <head>而不是 <body> 元素,才能保證在所有瀏覽器中的行為一致。
3、操作表格
<table> 元素是 HTML 中最復雜的結構之一。要想創建表格,一般都必須涉及表示表格行、單元格、表頭等方面的標簽。