10.1 節(jié)點層次
DOM可以將任何HTML和XML文檔描繪成一個由多層節(jié)點構成的結構,文檔節(jié)點只有一個子節(jié)點,即<html>元素,稱之為文檔元素,文檔元素是最外層元素,文檔中的其他所有元素都包含在文檔元素中,每個文檔只能有一個文檔元素。
10.1.1 Node類型
所有節(jié)點類型都繼承自Node類型,因此所有節(jié)點類型都共享相同的基本屬性和方法??偣灿?2種節(jié)點類型,每個節(jié)點都有一個nodeType屬性,用于表明節(jié)點類型,是一個常量。nodeName和nodeValue兩個屬性中保存著節(jié)點的信息。
每個節(jié)點都有一個childNodes屬性。其中保存著一個NodeList對象,用于保存一組有序的節(jié)點,它實際上是基于DOM結構動態(tài)執(zhí)行查詢的結果,因此DOM結構變化能夠自動反應在NodeList對象中。
// 將NodeList對象轉為數組
function toArray(nodes) {
var arr = [];
try {
arr = Array.prototype.slice.call(nodes,0);
}catch(ex){
// IE8以前需要枚舉所有成員
for(var i=0,len=nodes.length;i<len;i++){
arr.push(nodes[i]);
}
}
return arr;
}
每個節(jié)點都有parentNode屬性,指向文檔樹中的父節(jié)點。同一個childNodes列表中的所有節(jié)點都具有相同的父節(jié)點。因此它們的parentNode屬性都指向同一個節(jié)點。包含在childNodes列表中的每個節(jié)點相互之間都是同胞節(jié)點,previousSibling表示前一節(jié)點,nextSibling表示后一節(jié)點。父節(jié)點的firstChild表示childNodes列表中的第一個節(jié)點,lastChild表示childNodes列表中的最后一個節(jié)點。也可以用方括號表示。即firstChild等于childNodes[0],lastChild等于childNodes[childNodes.length-1]。節(jié)點的hasChildNodes()方法在節(jié)點包含一個或多個子節(jié)點時返回true。所有節(jié)點都有ownerDocument屬性,指向表示整個文檔的文檔節(jié)點。
appendChild()方法用于向childNodes列表末尾添加一個節(jié)點,并返回新添加的節(jié)點。如果傳給該方法的節(jié)點已經是文檔中的一部分,那結果就是將該節(jié)點從原來的位置轉移到新位置。
insertBefore()方法用于將節(jié)點插入childNodes列表中特定的位置,這個方法接收兩個參數,要插入的節(jié)點和作為參照的節(jié)點,插入后返回被插入的節(jié)點,參照節(jié)點為null時與appendChild()方法相同。
replaceChild()方法用于替換childNodes列表中的節(jié)點,這個方法接收兩個參數,要插入的節(jié)點和要替換的節(jié)點,要替換的節(jié)點會從文檔樹中被移除,并被這個方法返回。
removeChild()方法用于移除childNodes列表中的節(jié)點,接收一個參數,即被移除的節(jié)點,被移除的節(jié)點將作為返回值返回。
cloneNode()方法用于創(chuàng)建調用和這個方法的節(jié)點的一個完全相同的副本,始終接收一個布爾值參數,表示是否執(zhí)行深度復制,即復制節(jié)點及其整個子節(jié)點樹,在參數為false時,只執(zhí)行淺復制,即只復制節(jié)點本身。
10.1.2 Doucment類型
最常見的Doucment類型就是作為HTMLDocument實例的document對象。
document.documentElement屬性指向<html>元素;
document.body屬性指向<body>元素;
document.title屬性包含<title>元素中的文本,可以通過這個取得當前頁面的標題,也可以修改并反映在瀏覽器的標題中,但修改其值不會改變<title>元素;
document.URL屬性保存頁面完整的URL,即地址欄中顯示的URL。
document.domain屬性中包含當前頁面的域名。
document.referrer屬性中包含頁面來源的URL。
查找元素的方法:
document.getElementById(),按照元素ID進行查找;
document.getElementByTagName(),按照元素標簽名進行查找,返回HTMLCollection對象;
document.getElementByName(),按照元素標name特性進行查找,返回HTMLCollection對象;
HTMLCollection對象有一個namedItem()方法,可以根據元素的name特性取得HTMLCollection對象中對應的對象。
特殊合集:
document.anchors,包含文檔中所有帶有name特性的<a>元素;
document.forms,包含文檔中所有<form>元素,與document.getElementByTagName("form")相同;
document.images,包含文檔中所有<img>元素,與document.getElementByTagName("img")相同;
document.links,包含文檔中所有帶有href特性的<a>元素;
特殊合集中的內容會隨當前文檔的更新而更新。
10.1.3 Element類型
Element節(jié)點即元素節(jié)點,提供了對元素標簽名,子節(jié)點及特性的訪問。
nodeType值為1;
noadeName值為元素標簽名,與tagName值相同,輸出的元素標簽名為大寫;
<p id="a">asd</p>
console.log(document.getElementById("a").nodeType); // 1
console.log(document.getElementById("a").tagName); // P
console.log(document.getElementById("a").nodeName); // P
所有HTML元素都由HTMLElement類型表示,每個HTML元素都具有以下標準特性,下列特性均可以修改。
id,元素在文檔中的唯一標識符;
title,有關元素附加說明信息;
lang,元素內容語言代碼;
dir,語言的方向;
className,元素的class特性。
特性修改方法:
getAttribute(),接收一個字符串參數,為需要獲取的特性名稱,直接獲取傳入特性的值,也可以獲取自定義特性的值,并且不區(qū)分大小寫,只有公認的(非自定義)特性才會以屬性的形式添加到DOM對象當中,獲取style特性值得到的是CSS文本,通過屬性訪問style得到的是一個對象,獲取onclick之類事件處理程序特性值返回的是相應代碼的字符串,通過屬性訪問onclick之類事件處理程序得到的是一個JavaScript函數(未指定事件處理程序則返回null)。
<p id="a" myID="b">asd</p>
var p = document.getElementById("a");
console.log(p.id); // a
console.log(p.myID); // undefined
setAttribute(),接收兩個參數,一個為需要設置的特性名稱,一個為需要設置的特性的值,如果需要設置的特性已經存在,則替換原有的特性值。
removeAttribute(),接收一個字符串參數,徹底刪除元素的特性。
Element類型是使用attributes屬性的唯一一個DOM節(jié)點類型。attributes屬性中包含一個NamedNodeMap,與NodeList類型,是一個動態(tài)集合。每一個特性節(jié)點都保存在NamedNodeMap中,attributes屬性僅在需要遍歷元素特性的時候才用得到。每個特性節(jié)點都有一個specified屬性,如果這個屬性為true,則表示該特性要么是在HTML中指定的,要么是通過setAttribute()方法設置的。來自繼承的特性和方法都為false。
<p id="a" class="b" title="c" data-myID="x">asd</p>
var p = document.getElementById("a");
var obj = {};
for(var i = 0 ;i<p.attributes.length; i++){
if(p.attributes[i].specified){
obj[p.attributes[i].nodeName]=p.attributes[i].nodeValue;
}
}
console.log(obj); // {id: "a", class: "b", title: "c", data-myid: "x"}
使用document.createElement()可以創(chuàng)建新元素,傳入需要創(chuàng)建的新元素名稱,創(chuàng)建后就可以對其進行各種DOM操作,包括設置各種特性。但最后需要appendChild()、insertBefore()、replaceChild()等方法將其添加到DOM當中。
瀏覽器會將元素之間的空白符解釋為文本節(jié)點,如果需要通過childNodes屬性遍歷子節(jié)點,則需要對節(jié)點類型進行判斷后再執(zhí)行操作。
for(var i = 0 ;i<ele.childNodes.length; i++){
if(ele.childNodes[i].nodeType == 1){
// 執(zhí)行操作
}
}
每個元素應該只有一個文本子節(jié)點,使用normalize()方法可以將元素中的自文本節(jié)點合并成一個節(jié)點。
10.2 DOM操作技術
10.2.1 動態(tài)腳本
在頁面加載完成后動態(tài)加載外部javascript文件的通用方法。
function loadScript(url) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = url;
document.body.appendChild(script);
}
在頁面加載完成后動態(tài)加載外部javascript代碼片段的通用方法。
function loadScriptCode(code) {
var script = document.createElement("script");
script.type = "text/javascript";
// IE不允許訪問script元素的子節(jié)點,所以需要用script元素的text屬性來添加代碼片段。
try{
script.appendChild(document.createTextNode(code));
}catch(ex) {
script.text = code;
}
document.body.appendChild(script);
}
10.2.2 動態(tài)樣式
在頁面加載完成后動態(tài)加載外部CSS文件的通用方法。注意CSS代碼應該添加到head元素中,不是body元素中。
function loadStyle(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);
}
在頁面加載完成后動態(tài)加載外部CSS代碼片段的通用方法。
function loadStyleCode(code) {
var style = document.createElement("style");
style.type = "text/css";
// IE不允許訪問style元素的子節(jié)點,所以需要用style元素的styleSheet屬性的cssText屬性來添加代碼片段。
try {
style.appendChild(document.createTextNode(code));
}catch (ex){
style.styleSheet.cssText = code;
}
var head = document.getElementsByTagName("head")[0];
head.appendChild(style);
}
10.2.3 操作表格
<table>元素具有以下屬性和方法:
caption屬性,保存著對<caption>元素的指針;
tBodies屬性,<tbody>元素的HTMLCollection;
tFoot屬性,保存著對<tfoot>元素的指針;
tHead屬性,保存著對<thead>元素的指針;
rows屬性,表格中所有行的HTMLCollection;
creatTHead(),創(chuàng)建<thead>元素,將其放到表格中,返回引用;
creatTFoot(),創(chuàng)建<tfoot>元素,將其放到表格中,返回引用;
creatCaption(),創(chuàng)建<caption>元素,將其放到表格中,返回引用;
deleteTHead(),刪除<thead>元素;
deleteTFoot(),刪除<tfoot>元素;
deleteCaption(),刪除<caption>元素;
deleteRow(),刪除指定參數的行;
insertRow(),向rows集合中指定位置插入行。
<tbody>元素具有以下屬性和方法:
rows屬性,<tbody>元素中所有行的HTMLCollection;
deleteRow(),刪除指定參數的行;
insertRow(),向rows集合中指定位置插入行,返回對新插入行的引用。
<tr>元素具有以下屬性和方法:
cells屬性,<tr>元素中所有單元格的HTMLCollection;
deleteCells(),刪除指定參數的行;
insertCells(),向cells集合中指定位置插入單元格,返回對新插入單元格的引用。
10.2.4 使用NodeList
與NodeList類似的集合,NameNodeMap、HTMLCollection之類的,都是動態(tài)合集,文檔結構發(fā)生變化時,它們也會得到更新。如果要迭代一個NodeList,最好使用length屬性初始化第二個變量,以保證迭代的數量不會隨著迭代而發(fā)生變化。應盡量減少對NodeList的訪問,因為每次訪問NodeList,都會運行一次基于文檔的查詢,所以應當將NodeList中取得的值緩存起來,方便多次使用。