《JavaScript高級程序設計》Chapter 10 DOM

  • 以前提到過 DHTML->DOM
  • 本章介紹與瀏覽器相關的DOM節點以及JS對DOM的實現
  • 注意到,IE中的DOM都是經過COM實現的,與通常的DOM的運行機制有差別(考慮能力檢測、瀏覽器兼容)
  • 節點層次
    • 映射 
    • Node類型(一些通用的節點方法或者屬性) go
    • Document類型(注意<head>中一些網頁信息的處理) go
    • Element類型(訪問和處理元素屬性的幾種方法) go
    • Text類型(文本) go
    • Comment類型(註釋) go
    • CDATASection類型(針對XML) go
    • DocumentType類型(doctype) go
    • DocumentFragment類型(子節點樹的「倉庫」) go
    • Attr類型(屬性節點) go
  • DOM操做技術:動態腳本、動態樣式、表格<table>的操做、NodeList相關注意事項。go
 

節點層次

  • DOM將HTML或者XML文件映射成節點樹。從前瞭解的節點類型大體上分爲3種(元素節點、屬性節點和文檔節點),然而本書中進一步細分爲12種類型,繼承自一個基類型。
  • 每一個節點其實是一個節點對象,能夠經過獲取獲得,並調用相關屬性和方法進行處理。
  • DOM其實是一套API,提供了各類接口(節點類型接口)。
  • Node類型(一些通用的方法和屬性)
    • 存儲了一些節點的通用方法,其餘類型的節點都繼承了這個節點。可是須要注意IE8及以前的版本並不具有這個對象類型。
    • nodeType屬性。存儲了一些常量,表示節點類型。
    • nodeName和nodeValue屬性:顧名思義。並非全部節點的這兩個屬性有值,有時是null
    • 節點關係:構成了節點樹,訪問其餘節點的方法或者屬性:
      • childNodes屬性:動態的NodeList,是類數組對象,具備length。能夠經過Array.prototype.slice()轉換爲數組。注意IE8及以前的處理須要用遍歷的方法處理。
      • parentNode屬性
      • previousSibling屬性、nextSibling屬性
      • firstChild和lastChild屬性
      • hasChildNodes()方法
      • ownerDocument :指向DOM節點
      • 有些節點並不存在子節點,這裏會存在差別。
    • 操做節點:上述關係節點是隻讀的,能夠經過操做節點進行一些操做。
      • appendChild():注意到若是傳入的節點已是文檔的一部分了,那麼這個節點會轉移到新的位置(指針的改變)。
      • DOM中的節點不會同時出如今兩個或者多個DOM中
      • insertBefore(newNode, null/oldNode)
      • replaceChild(newNode, waitToReplacedNode)
      • 被代替的節點仍然存在在文檔中,只不過在文檔中沒了它的位置:各類指針關係已經不存在(或者被替代了)。沒法經過其餘節點訪問到它,因此說它沒有本身的位置
      • removeChild():只是移除
      • 這些操做是在「關係」的基礎上:主要由於DOM經過「關係」(指針)來訪問節點
    • 其餘方法:
      • cloneNode():只複製特性,不復制其餘操做(如事件處理)。IE這裏存在bug,建議複製以前,移除事件處理程序。
      • cloneNode(true):克隆節點以及其下完整的其餘節點
      • cloneNode(false):只複製該節點,須要藉助appendChild()等將其加入到文檔中。
      • normalize():處理異常的文檔節點(刪除空白文檔節點、合併相鄰的文檔節點)
  • Document類型
    • document與html的關係:document是HTMLDocument(繼承自Document類型)的一個實例。也是window對象的屬性。
    • Document節點特徵:
      • nodeType爲9
      • nodeName爲"#document"
      • nodeValue爲null
      • parentNode爲null
      • ownerDocument爲null
      • 其子節點多是DocumentType(最多一個)、Element(最多一個)、ProcessingInstruction或者Comment
    • 子節點
      • 多是DocumentType(最多一個)、Element(最多一個)、ProcessingInstruction或者Comment
      • document.documentElement:指向html
      • document.body:指向body
      • DocumentType:document.doctype處理<!DOCTYPE>。各瀏覽器處理方式不一樣
      • 註釋:各瀏覽器處理方式也不一樣
      • 因爲這些差別性存在,因此通常沒什麼用處。也不須要調用appendChild()等方法進行處理
    • 文檔信息(做爲HTMLDocument實例)
      • 網頁的信息(放在<head>中)
      • document.title:動態改變標題欄標題(文檔中的title屬性不變)
      • document.url/document.domain/document.referrer:
        • 不建議改變,沒多大用處:可是將多個框架的document.domain改一致,有助於通訊
        • domain不能夠改的徹底不一樣
        • 不可將鬆散的(wrox.com)改做緊繃的(p2p.wrox.com)
    • 查找元素
      • getElementById():區分大小寫,返回第一個找到的id(有時會返回同名的name,因此建議name和id屬性不要同樣)
      • getElementsByTagName():返回相似NodeList的HTMLCollection對象。
        • getElementsByTagName(*):順序返回全部元素
        • getElementsByTagName("*"):返回註釋元素
      • HTMLCollection對象:
        • 方括號傳入數字==調用item()方法
        • 方括號傳入字符==調用nameItem()方法經過name屬性獲取
      • getElementsByName():HTMLDocument類型的方法
      • TIPS:
        • 一、對於表單元素,id不一樣以使<label>元素應用到單個標籤
        • 二、name相同以確保三個值只有一個給瀏覽器
    • 特殊集合(HTMLDocument對象):document.anchors/document.applets(已不用)/document.forms/document.images/document.links
    • DOM一致性檢測:hasFeature()+必要的能力檢測
    • 文檔寫入:write()/writeln()/open()/close()
      • 注意寫入"<script>...</script>"的時候分開來,並寫做"<script>..."+"<\/script>"
      • 在文檔調用完畢以後執行write()/writeln()方法會重寫整個頁面
  • Element類型(元素節點),主要用於表現XML或者HTML文檔
    • 特徵:nodeType爲1,nodeName爲標籤名,nodeValue爲null,parentNode/子節點靈活。
    • nodeName屬性、tagName屬性訪問元素的標籤名,後者一概返回大寫,注意這點,尤爲在HTML文檔中,可所有處理成小寫。
    • HTML元素(由HTMLElement或者其子類型表示)
      • id/title/lang/dir/className屬性。注意到沒有用class是由於「class」是JS的保留字
      • 格式 div.id
    • 取得特性:getAttribute()/setAttribute()/removeAttribute()
      • getAttribute()能夠取得自定義特性(不區分大小寫,且HTML5中自定義特性須要加上data-前綴),而這些自定義屬性是不會調價到DOM元素的屬性中的(IE除外)。
    • 設置特性:setAttribute()、removeAttribute()
      • 會處理自定義屬性,特姓名統一轉換爲小寫
    • attributes屬性(處理屬性節點)
      • Element類型是使用這個屬性的惟一一個DOM節點類型
      • 包含相似NodeList的NamedNodeMap集合。
      • element.attributes.getNamedItem("id").nodeValue
        element.attributes["id"].nodeValue
        element.attributes.removeNamedItem("id")//返回刪除的屬性節點
        element.attributes.setNamedItem("newAttr");
      • 不常使用。能夠用在遍歷元素特性上。
      • 返回的特性的順序不必定。
    • 建立元素
      • document.creatElement("div")
      • IE中 :document.creatElement("html代碼")//避開IE的一些漏洞
    • 元素子節點:對於某個標籤下有多少個子節點的問題
      • IE只考慮元素類型
      • 其餘瀏覽器還會考慮換行符(文本類型)
      • 因此注意考慮nodeType
      • 固然可使用getElementById()或者getElementsByTagName()
    • 訪問or設置元素的屬性方法
      • HTMLElement或者子類型方法
      • getAttribute()/setAttribute()/removeAttribute()
      • DOM對象的屬性來訪問:不會設置自定義屬性
      • attributes屬性
      • 注意:style和onclick等在getAttribute()和DOM屬性調用中返回的不同:style經過getAttribute()返回CSS文本,屬性返回對象;onclick等經過屬性返回JS函數,getAttribute返回代碼的字符串。
      • 若以編程方式操做的時候,避免使用getAttribute();getAttribute()適合處理自定義屬性。
  • Text類型
    • 經過nodeValue屬性、data屬性以及createTextNode()等方式均可以訪問或者修改Text節點(可是注意,修改時傳入的字符串會通過HTML或XML的編碼)
    • createTextNode()建立文本節點
    • 在element上調用element.normalize()規範下面的文本節點
    • splitText(index)分割文本節點,分割到index前一個位置爲止。
    • 注意到:能夠經過lastChild訪問元素的文本節點(文本節點一般是元素的最後一個節點?)
  • Comment類型(註釋)
    • 不支持子節點,但能夠經過父節點訪問(comment.data)。
    • 與Text類型繼承自相同基類,擁有除了splitText()外的方法
    • document.createComment()
    • 少用。須要確保在<html></html>間,否則會有不一樣的處理方式(參照Document節點類型那裏的討論)
  • CDATASection類型(針對基於XML的文檔,表示CDATA區域)
    • 一樣繼承自Text類型,擁有除了splitText()外的方法
    • document.createCDataSection()
  • DocumentType類型
    • 僅FireFox、Safari、Opera和Chrome4.0支持
    • DOM1中不能動態建立,只能經過document.doctype訪問
    • 屬性:name、entities、notations;針對HTML和XHTML,後二者都是空列表。因此name屬性比較有用,保存文檔類型的名稱。
    • 以前也提到過,不一樣瀏覽器的處理方式不一樣。
  • DocumentFragment類型
    • 輕量級。只有它在文檔中沒有對應的標記。包含和控制節點,但不佔用額外資源。
    • 能夠作「倉庫」使用,保存未來可能會添加到文檔中的節點(待經過appendChild()等方法添加至樹中,或者從樹中移除的)
    • 建立:document.createDocumentFragment();
    • 文檔片斷,繼承了Node的全部方法。
    • 例如,爲ul添加3個li:
      var fragment = document.createDocumentFragment();
      var ul = document.getElementById("ul");
      var li = null;
      for (var i=0;i<3;i++){
          li = document.createElement("li");
          li.appendChild(document.createTextNode("Item"+(i+1));
          fragment.appendChild(li);
      }
      ul.appendChild(fragment); //fragment中的全部li被刪除並轉移到ul中
  • Attr類型(屬性類型)
    • 通常不認爲是節點樹中的成員,常使用其它方法訪問,而不是使用屬性節點進行操做。
    • 屬性:name/value/specified
    • document.createAttribute()
    • element.setAttributeNode(attr);//其中attr是屬性節點
      element.getAttributeNode(attr)

DOM操做技術

    • 動態腳本
      • 經過DOM動態添加JS腳本<script>
      • 添加外部腳本:什麼時候加載完畢沒法確認,但能夠經過「事件」進行控制。
      • 添加內嵌腳本:廣泛支持向script標記添加文本節點,但IE不容許訪問script的子節點,則可經過對script.text進行處理來添加這個內嵌腳本。
    • 動態樣式
      • 經過DOM動態應用CSS樣式:
      1. link添加樣式表;
      2. style添加嵌入樣式;
      3. 修改元素的屬性:
        • 修改元素的樣式屬性;
        • 修改元素的class屬性以匹配已存在的樣式
      • 外部樣式表是異步加載的,是否知道樣式表已經加載完成並不重要。但一樣能夠經過「事件」對這個過程進行檢測。
      • 對於<style>標記,IE一樣不能夠訪問其子節點,這個時候能夠經過style.stylesheet.cssText處理。注意處理這個屬性有可能致使瀏覽器崩潰。
    • 操做表格<table>元素
      • <table>,<tbody>/<thead>,<tr>,<th>/<td>對於多行多列的表格須要進行大量的重複性工做,HTML DOM爲此給<table>,<tbody>,<tr>增長了一些屬性和方法。
      • 還能夠利用document.write() or innerHTML寫入建立的代碼,其中行列能夠經過雙重for循環處理,注意須要採起儘可能少的調用innerHTML的循環算法,考慮內存的使用狀況。
    • 使用NodeList(如getElementsByTagName)的注意事項
      • 以及NamedNodeMap和HTMLCollection都是類數組對象,且都是動態的:文檔結構變化的時候,他們隨之改變(實時運行的查詢)
      • 每次從新訪問NodeList等的時候,都會從新對NodeList進行查詢,更新其length屬性,因此效率略低,應該減小對NodeList等的訪問,而且能夠將其中取得的值緩存起來使用(而不是每次都去查詢一遍)
      • 理解DOM的關鍵,就是理解DOM對性能的影響。DOM操做每每是JS程序最大的開銷部分
相關文章
相關標籤/搜索