第10章 DOM
1. 節點層次
文檔節點
是每個文檔的根節點。
(1) Node 類型
- 每個節點都有一個
nodeType
屬性,用于表明節點的類型。 - 節點類型由在 Node 類型中定義的下列 12 個數值常量來表示,任何節點類型必居其一:
(1) Node.ELEMENT_NODE(1);
(2) Node.ATTRIBUTE_NODE(2);
(3) Node.TEXT_NODE(3);
(4) Node.CDATA_SECTION_NODE(4);
(5) Node.ENTITY_REFERENCE_NODE(5);
(6) Node.ENTITY_NODE(6);
(7) Node.PROCESSING_INSTRUCTION_NODE(7);
(8) Node.COMMENT_NODE(8);
(9) Node.DOCUMENT_NODE(9);
(10) Node.DOCUMENT_TYPE_NODE(10);
(11) Node.DOCUMENT_FRAGMENT_NODE(11);
(12) Node.NOTATION_NODE(12)。
- IE 沒有公開 Node 類型的構造函數,為了確保跨瀏覽器兼容,最好還是將
nodeType 屬性與數字值
進行比較。
* nodeName
和 nodeValue
屬性
* 節點關系
- 每個節點都有一個
childNodes
屬性,其中保存著一個 NodeList 對象。
- 每個節點都有一個
- NodeList 是一種類數組 對象,用于保存一組有序的節點,可以通過位置來訪問這些節點。
- 雖然可以通過方括號語法來 訪問 NodeList 的值,而且這個對象也有
length 屬性
,但它并不是 Array 的實例
。- NodeList 對象的獨特之處在于,它實際上是
基于 DOM 結構動態執行查詢的結果
,因此 DOM 結構的變化能夠自動反映在 NodeList 對象中。
- 訪問保存在 NodeList 中的節點——可以通過方括號,也可以使用 item() 方法。
var firstChild = someNode.childNodes[0];
var secondChild = someNode.childNodes.item(1);
var count = someNode.childNodes.length;
- 將 NodeList 對象轉換為數組
function convertToArray(nodes){
var array = null;
try {
array = Array.prototype.slice.call(nodes, 0); //針對非 IE 瀏覽器
} catch (ex) {
array = new Array();
for (var i=0, len=nodes.length; i < len; i++){
array.push(nodes[i]);
}
}
return array;
}
- 每個節點都有一個
parentNode
屬性,該屬性指向文檔樹中的父節點。
- 每個節點都有一個
包含在 childNodes 列表中 的所有節點都具有相同的父節點,因此它們的 parentNode 屬性都指向同一個節點。
- 包含在 childNodes 列表中的每個節點相互之間都是同胞節點。通過使用列表中每個節點的
previousSibling
和nextSibling
屬性,可以訪問同一列表中的其他節點。
- 包含在 childNodes 列表中的每個節點相互之間都是同胞節點。通過使用列表中每個節點的
- 父節點的
firstChild
和lastChild
屬性分別指向其 childNodes 列表中的第一個和最后一個節點。
節點關系
- 父節點的
5.
hasChildNodes()方法
在節點包含一或多個子節點的情況下返回 true。-
ownerDocument屬性
指向表示整個文檔的文檔節點。
-
* 操作節點
-
appendChild()
方法:用于向 childNodes 列表的末尾添加一個節點。
如果傳入到 appendChild()中的節點已經是文檔的一部分了,那結果就是將該節點從原來的位置轉移到新位置。
//someNode 有多個子節點
var returnedNode = someNode.appendChild(someNode.firstChild);
alert(returnedNode == someNode.firstChild); //false
alert(returnedNode == someNode.lastChild); //true
-
insertBefore()
方法:接受兩個參數:要插入的節點
和作為參照的節點
。插入節點后,被插 入的節點會變成參照節點的前一個同胞節點(previousSibling),同時被方法返回。
如果參照節點是 null,則 insertBefore()與 appendChild()執行相同的操作
。
3.replaceChild()
方法:接受的兩個參數是:要插入的節點
和要替換的節點
。要替換的節點將由這個 方法返回并從文檔樹中被移除,同時由要插入的節點占據其位置。
4.removeChild()
方法:接受一個參數,即要移除 的節點。被移除的節點將成為方法的返回值。
* 其他方法
-
cloneNode()
方法:用于創建調用這個方法的節點的一個完全相同的副本。接受一個布爾值參數,表示是否執行深復制。在參數為 true 的情況下,執行深復制,也就是復制節點及其整個子節點樹;在參數為 false 的情況下,執行淺復制, 即只復制節點本身。
2.normalize()
方法:由于解析器的實現或 DOM 操作等原因,可能會出現文本節點不包含文本,或者接連出現兩個文本節點 的情況。當在某個節點上調用這個方法時,就會在該節點的后代節點中查找上述兩種情況。如果找到了空文本節點,則刪除它;如果找到相鄰的文本節點,則將它們合并為一個文本節點。
(2) Document類型
- JavaScript 通過 Document 類型表示文檔。
- 在瀏覽器中,document 對象是 HTMLDocument(繼承自 Document 類型)的一個實例,表示整個 HTML 頁面。
- document 對象是 window 對象的一個 屬性,因此可以將其作為全局對象來訪問。
Document 節點具有下列特征:
(1) nodeType 的值為 9;
(2) nodeName 的值為"#document";
(3) nodeValue 的值為 null;
(4) parentNode 的值為 null;
(5) ownerDocument 的值為 null;
(6) 其子節點可能是一個 DocumentType(最多一個)、Element(最多一個)、ProcessingInstruction
或 Comment。
* 文檔的子節點
Document 節點的子節點可以是DocumentType、Element、ProcessingInstruction 或 Comment。
1.兩個內置的訪問其子節點的快捷方式
:
documentElement 屬性
,該屬性始終指向 HTML 頁面中的<html>元素。- 通過 childNodes 列表訪問文檔元素。
-
document.body
,body 屬性,直接指向<body>元素。
3.Document 另一個可能的子節點是 DocumentType。通常將<!DOCTYPE>標簽看成一個與文檔其他 部分不同的實體,可以通過 doctype 屬性(在瀏覽器中是 document.doctype
)來訪問它的信息。
* 文檔信息
title屬性
:可以取得當前頁面的標題,也可以修改當前頁面的標題并反映在瀏覽器的標題欄中。(document.title
)URL屬性
:包含頁面完整的 URL(即地址欄中顯示的 URL)。(document.URL
)domain 屬性
:只包含頁面的域名。(document.domain)referrer 屬性
: 保存著鏈接到當前頁面的那個頁面的 URL。在沒有來源頁面的情況下,referrer 屬性中可能 會包含空字符串。(document.referrer)
(1) 只有
domain 是可以設置
的。但由于安全方面的限制,也并非可以給 domain 設 置任何值。如果 URL 中包含一個子域名,例如 p2p.wrox.com,那么就只能將 domain 設置為"wrox.com" (URL 中包含"www",如 www.wrox.com 時,也是如此)。不能將這個屬性設置為 URL 中不包含的域。
//假設頁面來自 p2p.wrox.com 域
document.domain = "wrox.com"; // 成功
document.domain = "nczonline.net"; // 出錯!
(2) 瀏覽器對 domain 屬性還有一個限制,即如果域名一開始是“松散的”(loose),那么不能將它再設 置為“緊繃的”(tight)。換句話說,在將 document.domain 設置為"wrox.com"之后,就不能再將其 設置回"p2p.wrox.com",否則將會導致錯誤。
//假設頁面來自于 p2p.wrox.com 域
document.domain = "wrox.com"; //松散的(成功)
document.domain = "p2p.wrox.com"; //緊繃的(出錯!)
*查找元素
getElementById()
(1) 接收一個參數:要取得的元素的 ID。如果找到相應的元素則返回該元素,如果不存在帶有相應 ID 的元素,則返回 null。
(2) 如果頁面中多個元素的 ID 值相同,getElementById()只返回文檔中第一次出現的元素
。
(3) ID 必須與頁面中元素的 id 特性(attribute)嚴格匹配
,包括大小寫
-
getElementsByTagName()
:
(1) 接受一個參數,即要取得元素的標簽名,而返回的是包含零或多個元素的 NodeList。
(2) 在 HTML 文檔中,這個方法會返回一 個HTMLCollection 對象
,作為一個“動態”集合,該對象與 NodeList 非常類似。
(3) 與 NodeList 對象類似,可以 使用方括號
語法或item()方法
來訪問 HTMLCollection 對象中的項。而這個對象中元素的數量則可以 通過其length 屬性
取得。
var images = document.getElementsByTagName("img");
alert(images.length);//輸出圖像的數量
alert(images[0].src); //輸出第一個圖像元素的 src 特性
alert(images.item(0).src);//輸出第一個圖像元素的 src 特性
(4) HTMLCollection 對象還有一個方法,叫做
namedItem()
,使用這個方法可以通過元素的 name 特性取得集合中的項。
<img src="myimage.gif" name="myImage">
var myImage = images.namedItem("myImage");
(5) HTMLCollection 還支持按名稱訪問項,對命名的項也可以使用方括號語法來訪問。
var myImage = images["myImage"];
對 HTMLCollection 而言,我們可以向方括號中傳入數值或字符串形式的索引值。在后臺,對數 值索引就會調用 item(),而對字符串索引就會調用 namedItem()。
(6) 要想取得文檔中的所有元素,可以向 getElementsByTagName()中傳入"*"。
3.getElementsByName()
:
(1) 只有 HTMLDocument 類型才有的方法,這個方法會返回帶有給定 name 特性的所有元素。
* 特殊集合
(1)
document.anchors
,包含文檔中所有帶 name 特性的<a>元素;
(2)document.applets
,包含文檔中所有的<applet>元素,因為不再推薦使用<applet>元素,所以這個集合已經不建議使用了;
(3)document.forms
,包含文檔中所有的<form>元素,與 document.getElementsByTagName("form")得到的結果相同;
(4)document.images
,包含文檔中所有的<img>元素,與 document.getElementsByTagName("img")得到的結果相同;
(5)document.links
,包含文檔中所有帶 href 特性的<a>元素。
* DOM 一致性檢測
由于 DOM 分為多個級別,也包含多個部分,因此檢測瀏覽器實現了 DOM 的哪些部分就十分必要 了。document.implementation 屬性
就是為此提供相應信息和功能的對象,與瀏覽器對 DOM 的實現直接對應。
(1) DOM1 級只為 document.implementation 規定了一個方法,即
hasFeature()
。這個方 法接受兩個參數:要檢測的 DOM 功能的名稱及版本號。如果瀏覽器支持給定名稱和版本的功能,則該方法返回 true。
var hasXmlDom = document.implementation.hasFeature("XML", "1.0");
* 文檔寫入
write()
和writeln()
方法都接受一個字符串參數,即要寫入到輸出流中的文本。write()會原樣寫入,而 writeln()則會 在字符串的末尾添加一個換行符(\n)。
(1) 在頁面被加載的過程中,可以使用這兩個方法向頁面中動態地加入內容。
<html>
<head>
<title>document.write() Example</title>
</head>
<body>
<p>The current date and time is:
<script type="text/javascript">
document.write("<strong>" + (new Date()).toString() +
"</strong>"); </script>
</p>
</body>
</html>
不能直接包含字符串"</script>",因為這會導致該 字符串被解釋為腳本塊的結束,它后面的代碼將無法執行。需加入轉義字符\即可
(2) 如果在文檔加載結束后再調用 document.write(),那么輸出的內容將會重寫整個頁面。
<html>
<head>
<title>document.write() Example 4</title>
</head>
<body>
<p>This is some content that you won't get to see
because it will be overwritten.</p>
<script type="text/javascript">
window.onload = function(){
document.write("Hello world!");
};
</script>
</body>
</html>
方法
open()
和close()
分別用于打開和關閉網頁的輸出流。如果是在頁面加載期間使用 write()或 writeln()方法,則不需要用到這兩個方法。
(3) Element類型
Element 類型用于表現XML或HTML 元素,提供了對元素標簽名、子節點及特性的訪問。
Element 節點具有以下特征:
(1) nodeType 的值為 1;
(2) nodeName 的值為元素的標簽名;
(3) nodeValue 的值為 null;
(4) parentNode 可能是 Document 或 Element;
(5) 其子節點可能是 Element、Text、Comment、ProcessingInstruction、CDATASection 或EntityReference。
- 要訪問元素的標簽名,可以使用
nodeName
屬性,也可以使用tagName
屬性; - 在 HTML 中,標簽名始終都以全部大寫表示,div.tagName 實際上輸出的是 "DIV"而非"div"。
*HTML元素
- 所有 HTML 元素都由
HTMLElement
類型表示,不是直接通過這個類型,也是通過它的子類型來表示。 - HTMLElement 類型直接繼承自 Element 并添加了一些屬性。添加的這些屬性分別對應于每個 HTML 元素中都存在的下列標準特性。
(1) id,元素在文檔中的唯一標識符。
(2) title,有關元素的附加說明信息,一般通過工具提示條顯示出來。
(3) lang,元素內容的語言代碼,很少使用。
(4) dir,語言的方向,值為"ltr"(left-to-right,從左至右)或"rtl"(right-to-left,從右至左),
也很少使用。
(5) className,與元素的 class 特性對應,即為元素指定的 CSS 類。
<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"
* 取得特性
getAttribute()
方法:
- 通過 getAttribute()方法也可以
取得自定義特性
(即標準 HTML 語言中沒有的特性)的值。
2.特性的名稱是不區分大小寫
的,即"ID"和"id"代表的都是同一個特性。
任何元素的所有特性,也都可以通過 DOM 元素本身的屬性來訪問。只有公認的(非自定義的)特性才會以屬性的形式添加到 DOM 對象中。
兩類特殊的特性屬性的值與通過 getAttribute()返回的值不相同:
(1) 第一類特性就是
style
,用于通過 CSS 為元素指定樣式。在通過 getAttribute()訪問時,返 回的 style 特性值中包含的是 CSS 文本,而通過屬性來訪問它則會返回一個對象。
(2) 第二類特性是onclick 這樣的事件處理程序
。當在元素上使用時,onclick 特性中包 含的是 JavaScript 代碼,如果通過 getAttribute()訪問,則會返回相應代碼的字符串。而在訪問 onclick 屬性時,則會返回一個 JavaScript 函數(如果未在元素中指定相應特性,則返回 null)。
* 設置特性
setAttribute()
方法:
- 這個方法
接受兩個參數
:要設置的特性名和值。如果特性已經存在,setAttribute()會以指定的值替換現有的值;如果特性不存在,setAttribute() 則創建該屬性并設置相應的值。 - 通過這個方法設置的 特性名會被統一轉換為
小寫形式
,即"ID"最終會變成"id"。
(1) 因為所有特性都是屬性,所以直接給屬性賦值可以設置特性的值。
(2) 為 DOM 元素添加一個自定義的屬性,該屬性不會自動成為元素的特性。
removeAttribute()
方法:
這個方法用于徹底刪除元素的特性
。調用這個方法不僅會清除特性的值,而且也會從元素中完全刪除特性。
*attributes 屬性
1.Element 類型是使用 attributes 屬性的唯一一個 DOM 節點類型。
2.attributes 屬性中包含一個NamedNodeMap,與 NodeList 類似,也是一個“動態”的集合。元素的每一個特性都由一個 Attr 節 點表示,每個節點都保存在 NamedNodeMap 對象中。
NamedNodeMap
對象擁有下列方法:
(1) getNamedItem(name):返回 nodeName 屬性等于 name 的節點;
(2) removeNamedItem(name):從列表中移除 nodeName 屬性等于 name 的節點;
(3) setNamedItem(node):向列表中添加節點,以節點的 nodeName 屬性為索引;
(4) item(pos):返回位于數字 pos 位置處的節點。
- attributes 屬性中包含一系列節點,每個節點的
nodeName 就是特性的名稱
,而節點的nodeValue 就是特性的值
。
var id = element.attributes.getNamedItem("id").nodeValue;
//簡寫方式
var id = element.attributes["id"].nodeValue;
//設置新值
element.attributes["id"].nodeValue = "someOtherId";
調用
removeNamedItem()方法
與在元素上調用 removeAttribute()方法的效果相同——直接刪 除具有給定名稱的特性。兩個方法間唯一的區別
,即 removeNamedItem()返回表示 被刪除特性的 Attr 節點。針對 attributes 對象中的特性,不同瀏覽器返回的
順序不同
。這些特性在 XML 或 HTML 代 碼中出現的先后順序,不一定與它們出現在 attributes 對象中的順序一致。IE7 及更早的版本會
返回 HTML 元素中所有可能的特性
,包括沒有指定的特性。換句話說,返回 100 多個特性的情況會很常見。
每個特 性節點都有一個名為
specified 的屬性
,這個屬性的值如果為 true,則意味著要么是在 HTML 中指定了相應特性,要么是通過 setAttribute()方法設置了該特性。在 IE 中,所有未設置過的特性的該 屬性值都為 false,而在其他瀏覽器中根本不會為這類特性生成對應的特性節點(因此,在這些瀏覽器 中,任何特性節點的 specified 值始終為 true)。
function outputAttributes(element){
var pairs = new Array(),
attrName,
attrValue,
i,
len;
for (i=0, len=element.attributes.length; i < len; i++){
attrName = element.attributes[i].nodeName;
attrValue = element.attributes[i].nodeValue;
if (element.attributes[i].specified) {
pairs.push(attrName + "=\"" + attrValue + "\"");
}
}
return pairs.join(" ");
}
* 創建元素
document.createElement()
方法可以創建新元素。
這個方法只
接受一個參數
,即要創建元素的標簽名。這個標簽名在
HTML 文檔中不區分大小寫
,而在 XML(包括 XHTML)文檔中,則是區 分大小寫的。在
IE 中
可以以另一種方式使用 createElement(),即為這個方法傳入完整的元素標簽,也可以包含屬性。
var div = document.createElement("<div id=\"myNewDiv\"
class=\"box\"></div >");
*元素的子節點
元素的 childNodes 屬性中包含了它的所有子節點,這些子節點有可能是元素、文本節點、注釋或處理指令。
不同瀏覽器在看待這些節點方面存在顯著的不同,返回的子節點不相同。
如果需要通過 childNodes 屬性遍歷子節點,要先檢查 一下 nodeTpye 屬性。
for (var i=0, len=element.childNodes.length; i < len; i++){
if (element.childNodes[i].nodeType == 1){ 12
//執行某些操作 }
}
- 元素也支持
getElementsByTagName()
方法。在通過元素調用這個方法時,除了搜索起點是當前元素之外,其他 方面都跟通過 document 調用這個方法相同,因此結果只會返回當前元素的后代。
var ul = document.getElementById("myList");
var items = ul.getElementsByTagName("li");
(4) Text 類型
-
文本節點
由 Text 類型表示,包含的是可以照字面解釋的純文本內容。 - 純文本中可以包含
轉義后的 HTML 字符
,但不能包含 HTML 代碼。
Text 節點具有以下特征
:
(1) nodeType 的值為 3;
(2) nodeName 的值為"#text";
(3) nodeValue 的值為節點所包含的文本; ? parentNode 是一個 Element;
(4) 不支持(沒有)子節點。
- 通過
nodeValue 屬性
或data 屬性
訪問 Text 節點中包含的文本,這兩個屬性中包含的值相同。對 nodeValue 的修改也會通過 data 反映出來,反之亦然。
操作節點中文本的方法
:
(1) appendData(text):將 text 添加到節點的末尾。
(2) deleteData(offset, count):從 offset 指定的位置開始刪除 count 個字符。
(3) insertData(offset, text):在 offset 指定的位置插入 text。
(4) replaceData(offset, count, text):用 text 替換從 offset 指定的位置開始到 offset+count 為止處的文本。
(5) splitText(offset):從 offset 指定的位置將當前文本節點分成兩個文本節點。
(6) substringData(offset, count):提取從 offset 指定的位置開始到 offset+count 為止
處的字符串。
文本節點還有一個
length 屬性
,保存著節點中字符的數目。而且,nodeValue.length 和 data.length 中也保存著同樣的值。在默認情況下,每個可以包含內容的元素
最多只能有一個文本節點
,而且必須確實有內容存在。
訪問文本子節點:
var textNode = div.firstChild; //或者div.childNodes[0]
//取得了文本節點的引用后修改它。
div.firstChild.nodeValue = "Some other message";
- 在修改文本節點時還要注意,此時的字
符串會經過 HTML
(或 XML,取決于文檔類型)編碼。換句話說, 小于號、大于號或引號都會像下面的例子一樣被轉義。
//輸出結果是"Some <strong>other</strong> message"
div.firstChild.nodeValue = "Some <strong>other</strong> message";
* 創建文本節點
document.createTextNode()
創建新文本節點。
- 這個方法接受一個參數——要插入節點 中的文本。
- 與設置已有文本節點的值一樣,作為參數的文本也將按照 HTML 或 XML 的格式進行編碼。
- 一般情況下,每個元素只有一個文本子節點。不過,在某些情況下也可能包含
多個文本子節點
。如果兩個文本節點是相鄰的同胞節點
,那么這兩個節點中的文本就會連起來顯示,中間不會有空格。
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);
*規范化文本節點
normalize()
方法:
如果 在一個包含兩個或多個文本節點的父元素上調用 normalize()方法,則會將所有文本節點合并成一個 節點,結果節點的 nodeValue 等于將合并前每個文本節點的 nodeValue 值拼接起來的值。
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!"
* 分割文本節點
splitText()
方法:
這個方法會將一個文本節點分成兩個文本節點,即按照指定的位置分割 nodeValue 值。原來的文本節點將包含從開始到指定位 置之前的內容,新文本節點將包含剩下的文本。這個方法會返回一個新文本節點,該節點與原節點的 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
(5) Comment類型
注釋在 DOM 中是通過 Comment 類型來表示的。
Comment 節點具有下列特征:
(1) nodeType 的值為 8;
(2) nodeName 的值為"#comment";
(3) nodeValue 的值是注釋的內容;
(4) parentNode 可能是 Document 或 Element;
(5) 不支持(沒有)子節點。
Comment 類型與 Text 類型繼承自相同的基類,因此它擁有除 splitText()之外的所有字符串操作方法。
與 Text 類型相似,也可以通過
nodeValue
或data 屬性
來取得注釋的內容。
3.document.createComment()
并為其傳遞注釋文本也可以創建注釋節點。
(6) CDATASection類型
- CDATASection 類型只針對
基于 XML 的文檔
,表示的是 CDATA 區域。 - 與 Comment 類似, CDATASection 類型繼承自 Text 類型,因此擁有除 splitText()之外的所有字符串操作方法。
CDATASection 節點具有下列特征:
(1) nodeType 的值為 4;
(2) nodeName 的值為"#cdata-section";
(3) nodeValue 的值是 CDATA 區域中的內容;
(4) parentNode 可能是 Document 或 Element; ? 不支持(沒有)子節點。
CDATA 區域只會出現在 XML 文檔中,因此多數瀏覽器都會把 CDATA 區域
錯誤地解析為 Comment 或 Element
。在真正的 XML 文檔中,可以使用
document.createCDataSection()
來創建 CDATA 區域,只需 為其傳入節點的內容即可。
(7) DocumentType類型
DocumentType 包含著與文檔的 doctype 有關的所有信息。
DocumentType具有下列特征:
(1) nodeType 的值為 10;
(2) nodeName 的值為 doctype 的名稱;
(3) nodeValue 的值為 null;
(4) parentNode 是 Document;
(5) 不支持(沒有)子節點。
- 在 DOM1 級中,DocumentType 對象
不能動態創建
,而只能通過解析文檔代碼的方式來創建。 - 支持它的瀏覽器會把 DocumentType 對象保存在
document.doctype
中。 - DOM1 級描述了 DocumentType 對象的
3 個屬性
:name、entities 和 notations。
(1)
name
表示文檔類型的名稱。
(2) entities 是由文檔類型描述的實體的 NamedNodeMap 對象
(3) notations 是由文檔類型描述的符號的 NamedNodeMap 對象。
* DocumentFragment類型
- 在所有節點類型中,只有 DocumentFragment 在文檔中
沒有對應的標記
。 - DOM 規定文檔片段 (document fragment)是一種“輕量級”的文檔,可以包含和控制節點,但不會像完整的文檔那樣占用
額外的資源。
DocumentFragment 節點具有下列特征:
(1) nodeType 的值為 11;
(2) nodeName 的值為"#document-fragment";
(3) nodeValue 的值為 null;
(4) parentNode 的值為 null;
(5) 子節點可以是 Element、ProcessingInstruction 、Comment、Text、CDATASection 或EntityReference。
- 雖然不能把文檔片段直接添加到文檔中,但可以將它作為一個“倉庫”來使用,即可以在里面保存將來可能會添加到文檔中的節點。
document.createDocumentFragment()方法
:創建文檔片段。
var fragment = document.createDocumentFragment();
- 如果將文檔中的節點添加到文檔片段中,就會從文檔樹中移除該節點,也不會從瀏覽器中再看到該節點。添加到文檔片段 中的新節點同樣也不屬于文檔樹。
- 可以通過 appendChild()或 insertBefore()將文檔片段中內容添 加到文檔中。在將文檔片段作為參數傳遞給這兩個方法時,實際上
只會將文檔片段的所有子節點添加到相應位置上
;文檔片段本身永遠不會成為文檔樹的一部分。
(5) Attr類型
元素的特性在 DOM 中以 Attr 類型來表示。
- 從技術角度講,特性就是存在于元素的 attributes 屬性中的節點。
特性節點具有 下列特征:
(1) nodeType 的值為 2;
(2) nodeName 的值是特性的名稱;
(3) nodeValue 的值是特性的值;
(4) parentNode 的值為 null;
(5) 在 HTML 中不支持(沒有)子節點;
(6) 在 XML 中子節點可以是 Text 或 EntityReference。
盡管它們也是節點,但特性卻不被認為是 DOM 文檔樹的一部分。
Attr 對象有
3 個屬性
:name、value 和 specified。
(1) name 是特性名稱(與 nodeName 的 值相同)。
(2) value 是特性的值(與 nodeValue 的值相同)。
(3) specified 是一個布爾值,用以區別特性是在代碼中指定的,還是默認的。
document.createAttribute()
并傳入特性的名稱可以創建新的特性節點。
setAttributeNode()
方法:將新創建的特性添加到元素中。
訪問特性:
attributes 屬性、getAttributeNode()方法以及 getAttribute()方法。其中,attributes和 getAttributeNode()都會返回對應特性的 Attr 節點,而 getAttribute()則只返回特性的值。
var attr = document.createAttribute("align");
attr.value = "left";
element.setAttributeNode(attr);
alert(element.attributes["align"].value);//"left"
alert(element.getAttributeNode("align").value); //"left"
alert(element.getAttribute("align")); //"left"
2. DOM 操作技術
(1) 動態腳本
創建動態腳本有兩種方式:插入外部文件
和直接插入 JavaScript 代碼
。
* 加載外部的 JavaScript 文件
function loadScript(url){
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
document.body.appendChild(script);
}
loadScript("client.js");
* 指定 JavaScript 代碼
function loadScriptString(code){
var script = document.createElement("script");
script.type = "text/javascript";
try {
script.appendChild(document.createTextNode(code));
} catch (ex){
script.text = code;
}
document.body.appendChild(script);
}
loadScriptString("function sayHi(){alert('hi');}");
IE 將<script>視為一個特殊的元素,不允許 DOM 訪問其子節點。不過,可以使用<script>元素的
text 屬性
來指定 JavaScript 代碼。
(2) 動態樣式
與動態腳本類似,所謂動態樣式是指在頁面剛加載時不存在的樣式;動態樣式是在頁面加載完成后動態添加到頁面中的。
- 能夠把 CSS 樣式包含到 HTML 頁面中的元素有兩個。其中,
<link>元素
用于包含來自外部的文件, 而<style>元素
用于指定嵌入的樣式。
*<link>元素
<link rel="stylesheet" type="text/css" href="styles.css">
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");
* <style>元素
<style type="text/css">
body {
background-color: red;
}
</style>
function loadStyleString(css){
var style = document.createElement("style");
style.type = "text/css";
try{
style.appendChild(document.createTextNode(css));
} catch (ex){
style.styleSheet.cssText = css;
}
var head = document.getElementsByTagName("head")[0];
head.appendChild(style);
}
loadStyleString("body{background-color:red}");
IE 將<style>視為 一個特殊的、與<script>類似的節點,不允許訪問其子節點。解決 IE 中這個問題的辦法,就是訪問元素的 styleSheet 屬性, 該屬性又有一個 cssText 屬性,可以接受 CSS 代碼。
(3) 操作表格
*<table>元素添加的屬性和方法
(1) caption:保存著對<caption>元素(如果有)的指針。
(2) tBodies:是一個<tbody>元素的 HTMLCollection。
(3) tFoot:保存著對<tfoot>元素(如果有)的指針。
(4) tHead:保存著對<thead>元素(如果有)的指針。
(5) rows:是一個表格中所有行的 HTMLCollection。
(6) createTHead():創建<thead>元素,將其放到表格中,返回引用。
(7) createTFoot():創建<tfoot>元素,將其放到表格中,返回引用。
(8) createCaption():創建<caption>元素,將其放到表格中,返回引用。 ? deleteTHead():刪除<thead>元素。
(9) deleteTFoot():刪除<tfoot>元素。
(10) deleteCaption():刪除<caption>元素。
(11) deleteRow(pos):刪除指定位置的行。
(12) insertRow(pos):向 rows 集合中的指定位置插入一行。
*為<tbody>元素添加的屬性和方法
(1) rows:保存著<tbody>元素中行的 HTMLCollection。
(2) deleteRow(pos):刪除指定位置的行。
(3) insertRow(pos):向 rows 集合中的指定位置插入一行,返回對新插入行的引用。
*<tr>元素添加的屬性和方法
(1) cells:保存著<tr>元素中單元格的 HTMLCollection。
(2) deleteCell(pos):刪除指定位置的單元格。
(3) insertCell(pos):向 cells 集合中的指定位置插入一個單元格,返回對新插入單元格的引用。
<table border="1" width="100%">
<tbody>
<tr>
<td>Cell 1,1</td>
<td>Cell 2,1</td>
</tr>
<tr>
<td>Cell 1,2</td>
<td>Cell 2,2</td>
</tr>
</tbody>
</table>
//創建 table
var table = document.createElement("table");
table.border = 1;
table.width = "100%";
//創建 tbody
var tbody = document.createElement("tbody");
table.appendChild(tbody);
//創建第一行
tbody.insertRow(0);
tbody.rows[0].insertCell(0);
tbody.rows[0].cells[0].appendChild(document.createTextNode("Cell 1,1"));
tbody.rows[0].insertCell(1);
tbody.rows[0].cells[1].appendChild(document.createTextNode("Cell 2,1"));
//創建第二行
tbody.insertRow(1);
tbody.rows[1].insertCell(0);
tbody.rows[1].cells[0].appendChild(document.createTextNode("Cell 1,2"));
tbody.rows[1].insertCell(1);
tbody.rows[1].cells[1].appendChild(document.createTextNode("Cell 2,2"));
//將表格添加到文檔主體中
document.body.appendChild(table);
(4) 使用NodeList
NodeList 及其“近親”NamedNodeMap 和 HTMLCollection,這三個集合都是“動態的”;換句話說,每當文檔結構發生變化時,它們都會得到更新。因 此,它們始終都會保存著最新、最準確的信息。
如果想要迭代一個 NodeList,最好是使用 length 屬性初始化第二個變量,然后將迭代器與該變量進行比較。
var divs = document.getElementsByTagName("div"),i,len, div;
for (i=0, len=divs.length; i < len; i++){
div = document.createElement("div");
document.body.appendChild(div);
}