雖然現在有著很多優秀的框架,但歸根結底我們依然得掌握好DOM知識來針對項目某些情況來使用原生操作,從而達到降低代碼的堆積,提高性能,提高頁面流暢的目的.
節點層次
Node類型
DOM1級定義了一個Node接口,由DOM中所有節點類型實現,除了IE外,其他瀏覽器都可以訪問到這個類型,Javascript中所有的節點類型都繼承自Node類型,因此所有節點類型都共享著相同的基本屬性和方法.
每個節點都有一個nodeType屬性,用于表明節點的類型,以下只列出常見的節點類型
節點類型
- Node.ELEMENT_NODE(1)
- Node.ATTRIBUTE_NODE(2)
- Node.TEXT_NODE(3)
- Node.CDATA_SECTION_NODE(4)
- Node.COMMENT_NODE(8)
將節點的nodeType屬性與上面字符串或者對應數字(建議)比較便可確知對應的節點類型
nodeName和nodeValue屬性
要了解節點的具體信息,可以使用這兩個屬性,不過這兩個屬性的值取決于節點的類型,所以使用之前最好做一下節點類型的檢測
- 元素節點:nodeName返回標簽名,nodeValue返回null
- 屬性節點:nodeName返回屬性名,nodeValue返回屬性值
- 文本節點:nodeName始終返回#text,node返回文本內容
節點關系
- childNodes
每個節點都有一個childNodes屬性,保存著一個NodeList對象,是一種類數組對象,保存著一組子節點,并且length屬性,特點是可以基于DOM結構動態執行查詢的結果,因此DOM結構的變化能夠自動反映在NodeList對象中
注意:節點的childNodes包含了節點內的所有節點類型(不包括屬性節點),而且標簽內的換行和空格都會被當成一個文本包含在childNodes屬性中
- parentNode
每個節點都有一個parentNode屬性,該屬性指向文檔樹種的父節點,因此,包含在childNodes列表中的所有節點都有相同的父節點,他們的parentNode屬性都指向同一個節點
- previousSibling 和nextSibling屬性
childNodes列表中的每個父節點相互之間都是同胞節點,可以通過每個節點的previousSibling和nextSibling屬性訪問同一列表的其他節點
- firstChild 和lastChild屬性
在父節點下使用這兩個屬性可以分別獲取childNodes列表下的第一個和最后一個節點.為部分需求操作提供的極大的便利
- hasChildNodes()
這個方法非常簡單實用,在節點包含一或多個子節點的情況下返回true,而無需查詢childNodes的length大小來判斷
- ownerDocument
所有節點都有的最后一個屬性是ownerDocument,該屬性指向整個文檔的文檔節點,不用層層回溯到頂端
操作節點
- appendChild(新增的節點)
接收一個新增節點作為參數 ,用于向childNodes列表的末尾添加一個節點,并返回新增的節點
- insertBefore(要插入的節點,作為參照的節點)
插入節點后,被插入的節點會變成參照節點的前一個同胞節點,同時被方法返回,如果參照節點是null,那么insertBefore()和appendChild()是等同的
- replaceChild(要插入的節點,要替換的節點)
要替換的節點將由這個方法返回并從文檔樹種移除,同時由要插入的節點占據其位置
- removeChild(要刪除的子節點)
這個方法接收一個參數,即要移除的節點,并且被方法返回
前面介紹的四個操作方法操作的都是某個節點的子節點,要使用必須先取得父節點,
在父節點上調用這些方法,否則會導致錯誤.
其他方法(所有類型節點都有)
- cloneNode(布爾值)
用于創建調用這個方法的節點的一個完全相同的副本,插入布爾值為true則表示深度復制,復制節點和其整個節點樹,否則為淺復制 ,只復制節點本身,復制后返回的節點文本屬于文檔所有,但成為一個"孤兒",需要添加到文檔樹中
注意:cloneNode()方法不會復制添加到DOM節點中的Javascript屬性或者事件處理程序等
- normalize()
處理文檔樹中的文本節點,如果在節點的后代節點中找到空文本節點,則刪除它,如果找到相鄰的文本節點,則將它們合并為一個文本節點
Document類型
Javascript是通過Document類型表示文檔,在瀏覽器中document對象是HTMLDocument的一個實例
表示整個頁面,而且document對象也是window對象的一個屬性,因此可以作為全局對象來訪問
Document節點具有以下特征
- nodeType的值為9
- nodeName: "#document"
- nodeValue: null
- parentNode: null
- ownerDocument: null
- 其子節點可能是一個DocumentType,Element,ProcessingInstruction或Comment
從document節點中取得頁面標簽
- document.documentElement指向HTML頁面中的<html>元素
- document.body指向<body>元素
- document.doctype可以取得對<!DOCTYPE>的引用
- document.title 包含<title>元素中的文本
從document節點中取得頁面的請求信息
- document.URL為地址欄中顯示的URL
- document.domain為頁面的域名
- document.referrer為連接到當前頁面的那個頁面的URL
從document節點中查找元素
- document.getElementById("mydiv")
- document.getElementsByTagName("img"),返回一個HTMLCollection對象,和NodeList對象類似,并且擁有一個方法namedItem()可以傳入元素的name特征來取得集合中的項,可以通過document.getElementsByTagName("*")獲取全部元素
- document.getElementsByName():這個方法會返回有給定name特征的所有元素,通常用來獲取單選按鈕.
- document.anchors:包含文檔中所有帶name特性的a元素
- document.forms:包含文檔中所有的form元素
- document.images:包含文檔中所有的img元素
- document.links:包含文檔中所有帶有href特性的a元素
DOM一致性檢測
由于DOM分為多個級別,因此檢測瀏覽器實現了DOM的哪些部分就十分有必要,doucment.implemention屬性就是為此提供相應的信息和功能的對象,與瀏覽器對DOM的實現直接對應
DOM1級只為document.implementation規定一個方法hasFeature()
接收兩個參數:①要檢測的DOM功能的名稱②版本號
方法返回是否支持的布爾值
如
var hasXmlDom = document.implmentation.hasFeatrue("XML","1.0")
文檔寫入
- document.write(寫入字符串):將輸出流寫入到網頁
- document.writeln(寫入字符串):將輸出流寫入到網頁并換行
注意:必要時候要加轉義字符\ - document.open()和document.close()分別用于打開和關閉網頁的輸出流,如果是在頁面加載期間使用write()或writeln()方法,則不需要用到這兩個方法,調用write或writeln方法時和結束時,瀏覽器會隱式調用這兩個方法
Element類型
判斷元素標簽的最佳實踐:
if(element.tagName.toLowerCase() == "div"){ //在此執行某些操作 }
HTML元素
每個HTML元素都有下列標準特性:
- id
- title
- lang :語言代碼
- dir :語言方向
- className :class特性
以上均可以通過作為該元素節點的屬性在javascript中獲取或修改
獲取和修改特性
- getAttribute(特性名稱)
不僅可以取得節點的默認特性也可以取得自定義特性(根據HTML5規范,自定義屬性應該加上data-前綴以便驗證),返回對應特性值
注意:傳入style特性后返回的是包含的CSS文本,而通過屬性來訪問style則返回一個對象,因為一系列的問題原因,平時開發只使用對象的屬性來獲取特性,而只有在取得自定義特性值的情況下,才會使用getAttribute()方法
- setAttribute(特性名稱,特性值)
如果特性存在,則用特性值進行修改,若不存在,則新建特性并賦予特性值,該方法不僅可以操作HTML特性也可以操作自定義特性,而使用對象屬性設置的自定義特性則不會自動成為元素的特性
- removeAttribute(要刪除的特性名稱)
這個方法用于徹底刪除元素的特性,不僅清除特性的值也會從元素中完全刪除特性
attributes屬性
Element類型是使用attributes屬性的唯一一個DOM節點類型,elment.attributes實質是該元素節點的所有屬性節點的結合,稱為NamedNodeMap,并且擁有它自己的特殊方法:
- getNamedItem(name) 返回nodeName屬性等于name的節點,即返回屬性名對應的屬性節點
- removeNamedItem(name):刪除該屬性節點
- setNamedItem(node) :向列表中添加屬性節點,以nodeName為索引
- item(po): 返回位于數字Pos位置處的節點
創建元素
- document.createElement(元素標簽名)
該方法可以傳入完整的元素標簽如
var div = document.createElement("div id=\"myNewDiv\" class = \"box\"></div>");
注意:這種形式創建的動態元素有很多已知的問題,若要創建一些跟別的元素或者存在相關事件處理的元素,不推薦用這種方法,如iframe標簽 input標簽 有name相同的單選按鈕等
元素的子節點
從上面就可以發現,用元素節點的childNodes遍歷其子元素節點會出現一些換行和空格等形成了文本節點的問題,這意味著在執行某項操作之前,都要檢查一下nodeType屬性,如:
for(var i = 0,len=element.childNodes.length;i<len;i++){ if(element.childNodes[i].nodeType == 1){ //執行某些操作 } }
Text類型
- nodeValue和data屬性:均可以用來訪問Text節點包含的文本
- appendData(text)
- deleteData(offset,count)
- insertData(offset,text)
- replaceData(offset,count,text)
- splitText(offset)
- substringData(offset,count)
- length屬性返回文本字符的數目
創建文本節點
document.createTextNode(要插入節點中的文本)
作為參數的文本將按照HTML或XML的格式進行編碼
規范化文本節點
即上面提及的normalize()方法
分割文本節點
與normalize()方法相反的splitText(pos)方法,將一個文本節點分成兩個文本節點
DocumentFragment類型
在所有的節點類型中,只有DocumentFragment在文檔中沒有對應的標記,DOM規范規定文檔片段是一種"輕量級"的文檔,可以包含和控制節點.雖然不能把文檔片段直接添加到文檔中,但可以將它作為一個"倉庫"來使用,即可以在里面保存將來可能添加到文檔中的節點
創建文檔片段
使用document.createDocumentFragment(),返回一個文檔片段對象,繼承了Node的所有方法,可以往里面堆積節點,然后一次性添加到文檔樹中,減低瀏覽器的渲染次數
Attr類型
不常單獨使用,不過多描述
Comment類型 ,CDATASection類型 ,DocumentType類型
不常單獨使用,不過多描述