JavaScript 高級程序設計(第10章 DOM)

第10章 DOM

1. 節點層次

文檔節點是每個文檔的根節點。

(1) Node 類型
  1. 每個節點都有一個 nodeType 屬性,用于表明節點的類型。
  2. 節點類型由在 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)。

  1. IE 沒有公開 Node 類型的構造函數,為了確保跨瀏覽器兼容,最好還是將nodeType 屬性與數字值進行比較。
nodeNamenodeValue 屬性
* 節點關系
    1. 每個節點都有一個 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;
    }
    1. 每個節點都有一個 parentNode屬性,該屬性指向文檔樹中的父節點。

包含在 childNodes 列表中 的所有節點都具有相同的父節點,因此它們的 parentNode 屬性都指向同一個節點。

    1. 包含在 childNodes 列表中的每個節點相互之間都是同胞節點。通過使用列表中每個節點的 previousSiblingnextSibling 屬性,可以訪問同一列表中的其他節點。
    1. 父節點的 firstChildlastChild 屬性分別指向其 childNodes 列表中的第一個和最后一個節點。
      節點關系
  • 5.hasChildNodes()方法在節點包含一或多個子節點的情況下返回 true。

    1. ownerDocument屬性指向表示整個文檔的文檔節點。
* 操作節點
  1. appendChild()方法:用于向 childNodes 列表的末尾添加一個節點。

如果傳入到 appendChild()中的節點已經是文檔的一部分了,那結果就是將該節點從原來的位置轉移到新位置。

//someNode 有多個子節點
var returnedNode = someNode.appendChild(someNode.firstChild);
alert(returnedNode == someNode.firstChild); //false 
alert(returnedNode == someNode.lastChild); //true
  1. insertBefore()方法:接受兩個參數:要插入的節點作為參照的節點。插入節點后,被插 入的節點會變成參照節點的前一個同胞節點(previousSibling),同時被方法返回。
    如果參照節點是 null,則 insertBefore()與 appendChild()執行相同的操作

3.replaceChild()方法:接受的兩個參數是:要插入的節點要替換的節點。要替換的節點將由這個 方法返回并從文檔樹中被移除,同時由要插入的節點占據其位置。

4.removeChild()方法:接受一個參數,即要移除 的節點。被移除的節點將成為方法的返回值。

* 其他方法
  1. cloneNode()方法:用于創建調用這個方法的節點的一個完全相同的副本。接受一個布爾值參數,表示是否執行深復制。在參數為 true 的情況下,執行深復制,也就是復制節點及其整個子節點樹;在參數為 false 的情況下,執行淺復制, 即只復制節點本身。

2.normalize()方法:由于解析器的實現或 DOM 操作等原因,可能會出現文本節點不包含文本,或者接連出現兩個文本節點 的情況。當在某個節點上調用這個方法時,就會在該節點的后代節點中查找上述兩種情況。如果找到了空文本節點,則刪除它;如果找到相鄰的文本節點,則將它們合并為一個文本節點。

(2) Document類型
  1. JavaScript 通過 Document 類型表示文檔。
  2. 在瀏覽器中,document 對象是 HTMLDocument(繼承自 Document 類型)的一個實例,表示整個 HTML 頁面。
  3. 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.兩個內置的訪問其子節點的快捷方式

  1. documentElement 屬性,該屬性始終指向 HTML 頁面中的<html>元素。
  2. 通過 childNodes 列表訪問文檔元素。
  1. document.body,body 屬性,直接指向<body>元素。

3.Document 另一個可能的子節點是 DocumentType。通常將<!DOCTYPE>標簽看成一個與文檔其他 部分不同的實體,可以通過 doctype 屬性(在瀏覽器中是 document.doctype)來訪問它的信息。

* 文檔信息
  1. title屬性:可以取得當前頁面的標題,也可以修改當前頁面的標題并反映在瀏覽器的標題欄中。(document.title)

  2. URL屬性:包含頁面完整的 URL(即地址欄中顯示的 URL)。(document.URL)

  3. domain 屬性:只包含頁面的域名。(document.domain)

  4. 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"; //緊繃的(出錯!)
*查找元素
  1. getElementById()

(1) 接收一個參數:要取得的元素的 ID。如果找到相應的元素則返回該元素,如果不存在帶有相應 ID 的元素,則返回 null。
(2) 如果頁面中多個元素的 ID 值相同,getElementById()只返回文檔中第一次出現的元素
(3) ID 必須與頁面中元素的 id 特性(attribute)嚴格匹配,包括大小寫

  1. 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");
DOM 功能
* 文檔寫入

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。

  1. 要訪問元素的標簽名,可以使用 nodeName 屬性,也可以使用 tagName 屬性;
  2. 在 HTML 中,標簽名始終都以全部大寫表示,div.tagName 實際上輸出的是 "DIV"而非"div"。
*HTML元素
  1. 所有 HTML 元素都由 HTMLElement 類型表示,不是直接通過這個類型,也是通過它的子類型來表示。
  2. 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()方法:

  1. 通過 getAttribute()方法也可以取得自定義特性(即標準 HTML 語言中沒有的特性)的值。

2.特性的名稱是不區分大小寫的,即"ID"和"id"代表的都是同一個特性。

任何元素的所有特性,也都可以通過 DOM 元素本身的屬性來訪問。只有公認的(非自定義的)特性才會以屬性的形式添加到 DOM 對象中。

兩類特殊的特性屬性的值與通過 getAttribute()返回的值不相同:

(1) 第一類特性就是 style,用于通過 CSS 為元素指定樣式。在通過 getAttribute()訪問時,返 回的 style 特性值中包含的是 CSS 文本,而通過屬性來訪問它則會返回一個對象。
(2) 第二類特性是onclick 這樣的事件處理程序。當在元素上使用時,onclick 特性中包 含的是 JavaScript 代碼,如果通過 getAttribute()訪問,則會返回相應代碼的字符串。而在訪問 onclick 屬性時,則會返回一個 JavaScript 函數(如果未在元素中指定相應特性,則返回 null)。

* 設置特性

setAttribute()方法:

  1. 這個方法 接受兩個參數:要設置的特性名和值。如果特性已經存在,setAttribute()會以指定的值替換現有的值;如果特性不存在,setAttribute() 則創建該屬性并設置相應的值。
  2. 通過這個方法設置的 特性名會被統一轉換為小寫形式,即"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 位置處的節點。

  1. attributes 屬性中包含一系列節點,每個節點的nodeName 就是特性的名稱,而節點的 nodeValue 就是特性的值
var id = element.attributes.getNamedItem("id").nodeValue;
//簡寫方式
var id = element.attributes["id"].nodeValue;
//設置新值
element.attributes["id"].nodeValue = "someOtherId";
  1. 調用 removeNamedItem()方法與在元素上調用 removeAttribute()方法的效果相同——直接刪 除具有給定名稱的特性。兩個方法間唯一的區別,即 removeNamedItem()返回表示 被刪除特性的 Attr 節點。

  2. 針對 attributes 對象中的特性,不同瀏覽器返回的順序不同。這些特性在 XML 或 HTML 代 碼中出現的先后順序,不一定與它們出現在 attributes 對象中的順序一致。

  3. 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()方法可以創建新元素。

  1. 這個方法只接受一個參數,即要創建元素的標簽名。

  2. 這個標簽名在 HTML 文檔中不區分大小寫,而在 XML(包括 XHTML)文檔中,則是區 分大小寫的。

  3. IE 中可以以另一種方式使用 createElement(),即為這個方法傳入完整的元素標簽,也可以包含屬性。


var div = document.createElement("<div id=\"myNewDiv\" 
class=\"box\"></div >");
*元素的子節點
  1. 元素的 childNodes 屬性中包含了它的所有子節點,這些子節點有可能是元素、文本節點、注釋或處理指令。

  2. 不同瀏覽器在看待這些節點方面存在顯著的不同,返回的子節點不相同。

  3. 如果需要通過 childNodes 屬性遍歷子節點,要先檢查 一下 nodeTpye 屬性。

for (var i=0, len=element.childNodes.length; i < len; i++){
if (element.childNodes[i].nodeType == 1){ 12
//執行某些操作 }
}
  1. 元素也支持 getElementsByTagName()方法。在通過元素調用這個方法時,除了搜索起點是當前元素之外,其他 方面都跟通過 document 調用這個方法相同,因此結果只會返回當前元素的后代。
var ul = document.getElementById("myList");
var items = ul.getElementsByTagName("li");
(4) Text 類型
  1. 文本節點由 Text 類型表示,包含的是可以照字面解釋的純文本內容。
  2. 純文本中可以包含轉義后的 HTML 字符,但不能包含 HTML 代碼。

Text 節點具有以下特征:

(1) nodeType 的值為 3;
(2) nodeName 的值為"#text";
(3) nodeValue 的值為節點所包含的文本; ? parentNode 是一個 Element;
(4) 不支持(沒有)子節點。

  1. 通過 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 為止
處的字符串。

  1. 文本節點還有一個 length 屬性,保存著節點中字符的數目。而且,nodeValue.length 和 data.length 中也保存著同樣的值。

  2. 在默認情況下,每個可以包含內容的元素最多只能有一個文本節點,而且必須確實有內容存在。

訪問文本子節點:

var textNode = div.firstChild; //或者div.childNodes[0]
//取得了文本節點的引用后修改它。
div.firstChild.nodeValue = "Some other message";
  1. 在修改文本節點時還要注意,此時的字符串會經過 HTML(或 XML,取決于文檔類型)編碼。換句話說, 小于號、大于號或引號都會像下面的例子一樣被轉義。
//輸出結果是"Some &lt;strong&gt;other&lt;/strong&gt; message" 
div.firstChild.nodeValue = "Some <strong>other</strong> message";
* 創建文本節點

document.createTextNode()創建新文本節點。

  1. 這個方法接受一個參數——要插入節點 中的文本。
  2. 與設置已有文本節點的值一樣,作為參數的文本也將按照 HTML 或 XML 的格式進行編碼。
  3. 一般情況下,每個元素只有一個文本子節點。不過,在某些情況下也可能包含多個文本子節點。如果兩個文本節點是相鄰的同胞節點,那么這兩個節點中的文本就會連起來顯示,中間不會有空格。
    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) 不支持(沒有)子節點。

  1. Comment 類型與 Text 類型繼承自相同的基類,因此它擁有除 splitText()之外的所有字符串操作方法。

  2. 與 Text 類型相似,也可以通過nodeValuedata 屬性來取得注釋的內容。

3.document.createComment()并為其傳遞注釋文本也可以創建注釋節點。

(6) CDATASection類型
  1. CDATASection 類型只針對基于 XML 的文檔,表示的是 CDATA 區域。
  2. 與 Comment 類似, CDATASection 類型繼承自 Text 類型,因此擁有除 splitText()之外的所有字符串操作方法。

CDATASection 節點具有下列特征:

(1) nodeType 的值為 4;
(2) nodeName 的值為"#cdata-section";
(3) nodeValue 的值是 CDATA 區域中的內容;
(4) parentNode 可能是 Document 或 Element; ? 不支持(沒有)子節點。

  1. CDATA 區域只會出現在 XML 文檔中,因此多數瀏覽器都會把 CDATA 區域錯誤地解析為 Comment 或 Element

  2. 在真正的 XML 文檔中,可以使用document.createCDataSection()來創建 CDATA 區域,只需 為其傳入節點的內容即可。

(7) DocumentType類型

DocumentType 包含著與文檔的 doctype 有關的所有信息。
DocumentType具有下列特征:

(1) nodeType 的值為 10;
(2) nodeName 的值為 doctype 的名稱;
(3) nodeValue 的值為 null;
(4) parentNode 是 Document;
(5) 不支持(沒有)子節點。

  1. 在 DOM1 級中,DocumentType 對象不能動態創建,而只能通過解析文檔代碼的方式來創建。
  2. 支持它的瀏覽器會把 DocumentType 對象保存在 document.doctype 中。
  3. DOM1 級描述了 DocumentType 對象的 3 個屬性:name、entities 和 notations。

(1) name表示文檔類型的名稱。
(2) entities 是由文檔類型描述的實體的 NamedNodeMap 對象
(3) notations 是由文檔類型描述的符號的 NamedNodeMap 對象。

* DocumentFragment類型
  1. 在所有節點類型中,只有 DocumentFragment 在文檔中沒有對應的標記
  2. DOM 規定文檔片段 (document fragment)是一種“輕量級”的文檔,可以包含和控制節點,但不會像完整的文檔那樣占用
    額外的資源。
    DocumentFragment 節點具有下列特征:

(1) nodeType 的值為 11;
(2) nodeName 的值為"#document-fragment";
(3) nodeValue 的值為 null;
(4) parentNode 的值為 null;
(5) 子節點可以是 Element、ProcessingInstruction 、Comment、Text、CDATASection 或EntityReference。

  1. 雖然不能把文檔片段直接添加到文檔中,但可以將它作為一個“倉庫”來使用,即可以在里面保存將來可能會添加到文檔中的節點。

document.createDocumentFragment()方法:創建文檔片段。

var fragment = document.createDocumentFragment();
  1. 如果將文檔中的節點添加到文檔片段中,就會從文檔樹中移除該節點,也不會從瀏覽器中再看到該節點。添加到文檔片段 中的新節點同樣也不屬于文檔樹。
  2. 可以通過 appendChild()或 insertBefore()將文檔片段中內容添 加到文檔中。在將文檔片段作為參數傳遞給這兩個方法時,實際上只會將文檔片段的所有子節點添加到相應位置上;文檔片段本身永遠不會成為文檔樹的一部分。
(5) Attr類型

元素的特性在 DOM 中以 Attr 類型來表示。

  1. 從技術角度講,特性就是存在于元素的 attributes 屬性中的節點。

特性節點具有 下列特征:

(1) nodeType 的值為 2;
(2) nodeName 的值是特性的名稱;
(3) nodeValue 的值是特性的值;
(4) parentNode 的值為 null;

(5) 在 HTML 中不支持(沒有)子節點;
(6) 在 XML 中子節點可以是 Text 或 EntityReference。

  1. 盡管它們也是節點,但特性卻不被認為是 DOM 文檔樹的一部分。

  2. 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) 動態樣式

與動態腳本類似,所謂動態樣式是指在頁面剛加載時不存在的樣式;動態樣式是在頁面加載完成后動態添加到頁面中的。

  1. 能夠把 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);
 }

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容