跳到主要內容
黯羽輕揚每天積累一點點

JS 學習筆記 5_DOM

免費2015-04-09#JS#dom

本文介紹各種 DOM 節點,DOM 操作以及性能優化策略。

##1.DOM 節點的常用屬性(所有節點都支援)##

  1. nodeType:元素 1,屬性 2,文本 3

  2. nodeName:元素標籤名的大寫形式

  3. nodeValue:元素節點為 null,文本節點為文本內容,屬性節點為屬性值

  4. 關係屬性:parentNode,childNodes,nextSibling,previousSibling,firstChild,lastChild

  5. ownerDocument:文檔節點(document 物件)

##2.操作 DOM 節點(增/刪/改)##

  1. appendChild(node);給當前節點的 childNodes 列表末尾添加一個節點。若 node 已存在,則把 node 移動到當前節點下

  2. insertBefore(node, targetNode);在 targetNode 前插入 node

  3. replaceChild(node, targetNode);用 node 替換 targetNode,注意:替換之後 targetNode並沒有被銷毀,只是變成了遊離在 DOM 樹外的文檔碎片

  4. removeChild(node);移除 node,注意:移除之後 node也沒有被銷毀,該方法返回 node 的引用

  5. cloneNode(true/false);複製一個與當前節點完全相同的節點,若 true 則深複製,否則淺複製,IE 會複製相關事件處理器,其它瀏覽器不會

  6. normalize();用來刪掉空文本節點,合併相鄰文本節點

##3.document 物件相關##

  1. document.documentElement;指向元素

  2. document.body;指向元素

  3. document.title;指向元素,直接賦值可以修改文檔標題

  4. document.URL;獲取完整 URL

document.domain;獲取域名,可以直接賦值設置域名,當頁面中多個 frame 需要通信時必須修改該屬性,以解除跨域安全限制

document.referrer;獲取上一個頁面的 url,可能是空串

  1. 查找元素

    • document.getElementById(str);

    • document.getElementsByTagName(str);返回集合,用方括號語法訪問,方括號內可以是字符串表示按 name 屬性值取元素(str 可以是*表示取所有 DOM 元素)

    • document.getElementsByName(str);多用於單選按鈕組

P.S.前兩個適用於所有 XML 文檔的 DOM 操作,最後一個只適用於 HTML 文檔。至於 HTML5 支援的 document.querySelector(str) 以及 document.getElementsByClassName(str) 不在此討論,上面列出的 3 種方式都是全瀏覽器相容的

  1. document.write(str);文檔寫入,文檔加載過程中直接調用則在指定位置輸出內容,若放在 load 事件處理器中則重寫整個頁面

  2. document.createTextNode(text);創建文本節點。document.createElement(tagName);創建元素

##4.元素節點相關##

  1. 元素節點的屬性:id、title(類似於 ToolTip)、className,都是可讀/寫的(寫原生 js 代碼時這 3 個屬性很常用,尤其是className,很方便)

  2. elem.getAttribute(attr);獲取 attr 屬性的值,也可以取得自定義屬性,但 HTML5 中自定義屬性應該加上"data-"前綴(當然,不加也沒關係,只是規範要求),用 elem.dataset.attr 獲取

elem.setAttribute(attr, value);設置屬性值,只用來設置自定義屬性,因為自定義屬性無法直接設置

elem.removeAttribute(attr);刪除屬性和值([IE6-]不支援

P.S.一般直接訪問屬性,例如 elem.id, elem.style 等等,get/setAttribute 方式並不常用(只用來讀/寫自定義屬性),因為用函數方式訪問 style 和 onclick 或其它事件屬性返回字符串,而直接訪問可以返回可操作物件(比如函數引用),所以一般都直接訪問元素屬性

  1. attributes 屬性:elem.attributes['id'].nodeValue = value;也可以通過這種方式來訪問屬性,但更多的時候用 attributes 屬性來遍歷元素屬性

  2. 遍歷元素的節點時應該添加 nodeType 檢測,因為有些瀏覽器會把標籤間的空白字符也當作節點(Unicode 簽名 BOM

##5.文本節點##

node.nodeValue 或者 node.data 都可以訪問文本內容

##6.DOM 性能優化##

  1. 盡量減少訪問 NodeList 的次數

NodeList、NamedNodeMap、HTMLCollection 都是實時更新的,document.getElementByxxx 的返回值就是該類型的。應該盡量減少訪問 NodeList 的次數,因為訪問時需要檢查 DOM 樹,存在不小的性能損耗。可以把 NodeList 物件的引用保存起來,例如不要出現下面的代碼:

    for(var i = 0;i < 100;i++){
      document.getElementsByTagName('li')[i].className = 'disabled';
    }

這樣做簡直太傷了,更好的做法是:

    var lis = document.getElementsByTagName('li');
    for(var i = 0;i < 100;i++){
      lis[i].className = 'disabled';
    }

常見的 HTMLCollection 物件有:document.forms、document.images、document.links、document.anchors

  1. 使用 DocumentFragment 避免多次「現場更新」

DocumentFragment 是一種比較冷门但非常有用的節點,在性能優化中尤其重要,需要插入大量 DOM 節點時,我們有兩個選擇:要麼一個一個往 DOM 樹上插,要麼先插到文檔碎片上,再把文檔碎片插入 DOM 樹。第一種方式需要更新 n 次 DOM 樹,而第二種方式只需要更新 1 次,例如:

    //創建文檔碎片
    var frag = document.createDocumentFragment();
    //插入節點
    var node = null, text = null;
    for(var i = 0;i < 10;i++){
      node = document.createElement('p');
      text = document.createTextNode('段落' + i);
      node.appendChild(text);
      frag.appendChild(node);
    }
    //把攜帶著節點的文檔碎片插入 DOM 樹
    document.body.appendChild(frag);

文檔碎片在 DOM 樹中是不存在的,把碎片插入 DOM 樹實際上是插入了它攜帶的節點,文檔碎片是一個看不見的容器。當然也可以創建一個 div 作為容器,和創建文檔碎片道理一樣,只要能避免 n 次現場更新就好,因為 DOM 樹上任何一個節點更新時瀏覽器都會重新渲染頁面,這意味著大量的樣式數值計算

  1. getElementByxxx 的性能差異

Id 查詢是最快的,TagName 次之,ClassName 最慢。當然,一般情況下這些差異是可以忽略的,但移動端頁面應該充分考慮,畢竟移動端沒有 PC 這麼好的條件。此外,把頻繁使用的元素的引用保存一份可以減少不必要的 DOM 查找,從而提升性能。

##7.動態創建 img/script/link 元素##

鑒於這部分內容和一般的 DOM 操作不同,和事件的關聯比較多,所以放在[JS 學習筆記 6_事件](http://ayqy.net/blog/js 學習筆記 6_事件/)中詳述

評論

暫無評論,快來發表你的看法吧

提交評論