你不知道的那些DOM

DOM變化

DOM2級和3級的目的在於擴展DOM API,以知足操做XML的全部需求,同時提供更好的錯誤處理及特性檢測能力。從某種意義上講,實現這一目的的很大程度意味着對命名空間的支持。css

var supportsDOM2Core = document.implementation.hasFeature('Core', '2.0');

var supportsDOM3Core = document.implementation.hasFeature('Core', '3.0');

var supportsDOM2HTML = document.implementation.hasFeature('HTML', '2.0')

var supportsDOM2Views = document.implementation.hasFeature('Views', '2.0');

var supportsDOM2XML = document.implementation.hasFeature('XML', '2.0')
複製代碼

針對XML命名空間的變化

有了XML命名空間,不一樣XML文檔的元素就能夠混合一塊兒,共同構成格式良好的文檔,而沒必要擔憂發生命名衝突。html

命名空間要使用xmlns特性來指定。node

<html xmlns='http://www.w3.org/1999/xhtml'>
    <head>
        <title>Example XHTML page</title>
    </head>
    <body>
        Hello world!
    </body>
</html>
複製代碼

Node類型的變化

在DOM2級中,Node類型包含下列特定於命名空間的屬性。編程

  • localName: 不帶命名空間前綴的節點名稱
  • namespaceURI: 命名空間URI或者(在未指定的狀況下是)null
  • prefix: 命名空間前綴或者(未指定的狀況下是)null

其餘方面的變化

DOM的其餘部分在‘DOM2級核心’中也發生了一些變化。這些變化與XML命名空間無關,而是更傾向於確保API的可靠性及完整性。瀏覽器

DocumentType類型的變化

新增了3個屬性:publicId、systemId和internalSubset。bash

Document類型的變化

Document類型的變化中惟一與命名空間無關的方法是importNode()。app

須要注意的是,每一個節點都有一個ownerDocument屬性,表示所屬的文檔。若是調用appendChild()時傳入的節點屬於不一樣的文檔(ownerDocument屬性的值不同),則會致使錯誤。但在調用importNode()時傳入不一樣文檔的節點則會返回一個新節點,這個新節點的全部權歸當前文檔全部。框架

importNode()方法與Element的cloneNode()方法很是相似,它接受兩個參數:要複製的節點和一個表示是否複製子節點的布爾值。
返回的結果是原來節點的副本,但可以在當前文件中使用。函數

var newNode = document.importNode(oldNode, true);  //導入節點及其子節點

document.body.appendChild(newNode);
複製代碼

Node類型的變化

Node類型中惟一與命名空間無關的變化,就是添加了isSupported()方法。與DOM1級爲document.implementation引入的hasFeature()方法相似,isSupported()方法用於肯定當前節點具備什麼能力。ui

DOM3級引入了兩個輔助比較節點的方法:isSameNode()和isEqualNode()。 這兩個方法都接受一個節點參數,並在傳入節點與引用的節點相同或相等時返回true。
所謂相同,指的是兩個節點引用的是同一個對象。
所謂相等,指的是兩個節點是相同的類型,具備相等的屬性(nodeName、nodeValue),並且它們的attributes和childNodes屬性也相等。

var div1 = document.createElement('div');

div1.setAttribute('class', 'box');

var div2 = docuemnt.createElement('div');

div2.setAttribute('class', 'box');

div1.isSameNode(div1);  // true
div1.isSameNode(div2); // false
div1.isEqualNode(div2); // true
複製代碼

框架的變化

樣式

在HTML中定義樣式的方式有3種:經過<link/>元素包含外部樣式表文件、使用<style/>元素定義嵌入式樣式,以及使用style特性定義針對特定元素的樣式。

DOM2級樣式模塊圍繞這3種應用樣式的機制提供了一套API。

訪問元素的樣式

任何支持style特性的HTML元素在JavaScript中都有一個對應的style屬性。這個style對象是CSSStyleDeclaration的實例,包含着經過HTML的style特性指定的全部樣式信息,但不包含與外部樣式表或嵌入樣式表經層疊而來的樣式。

對於短劃線的CSS屬性名,必須將其轉換成駝峯大小寫形式,才能經過JavaScript訪問。

  • background-image -> style.backgroundImage
  • font-family -> style.fontFamily

其中一個不能直接轉換的CSS屬性就是float。因爲float是JavaScript中的保留字,所以不能用做屬性名。規定對應的屬性名是cssFloat。而IE中則是styleFloat。

DOM樣式屬性和方法

DOM2級樣式規範還爲style對象定義了一些屬性和方法。這些屬性和方法在提供元素的style特性值的同時,也能夠修改樣式。下面列出了這些屬性和方法。

  • cssText
  • length
  • parentRule
  • getPropertyCSSValue(propertyName)
  • getPropertyPriority(propertyName)
  • getPropertyValue(propertyName): 返回給定屬性的字符串值
  • item(index): 返回給定位置的CSS屬性的名稱
  • removeProperty(propertyName):從樣式中刪除給定屬性。
  • setProperty(propertyName, value, priority)

設置cssText是爲元素應用多項變化最快捷的方式:

myDiv.style.cssText = 'width: 25px; height: 100px'
複製代碼

迭代CSS屬性:

var prop, value, i, len;

for (i = 0; len = myDiv.style.length; i < len; i++) {
    prop = myDiv.style[i];  //或者 myDiv.style.item(i)
    
    value = myDiv.style.getPropertyValue(prop);
    
    console.log(prop + ' : ' + value)
}
複製代碼

計算的樣式

getComputedStyle()方法。這個方法接受兩個參數:要取得計算樣式的元素和一個僞元素字符串。若是不須要僞元素信息,第二個參數能夠是null。

var myDiv = document.getElementById('myDiv');

var computedStyle = myDiv.computedStyle // IE環境下 myDiv.currentStyle
複製代碼

這個屬性是CSSStyleDeclaration的實例。

操做樣式表

CSSStyleSheet對象是一套只讀的接口(有一個屬性例外)。使用下面的代碼能夠肯定瀏覽器是否支持DOM2級樣式表。

var supportDOM2StyleSheets = dcoument.implementation.hasFeature('StyleSheets', '2.0');
複製代碼

CSSStyleSheet繼承自StyleSheet,後者能夠做爲一個基礎接口來定義非CSS樣式表。從StyleSheet接口繼承而來的屬性以下。

  • disabled: 表示樣式表是否被禁用的布爾值。
  • href:若是樣式表是經過包含的,則是樣式表的URL,不然是null
  • media:當前樣式表支持的全部媒體類型的集合
  • ownerNode: 指向擁有當前樣式的節點的指針,樣式表多是在HTML中經過<link><style/>引入的。若是當前樣式表是其餘樣式表經過@import導入的,則這個屬性值爲null。IE不支持這個屬性。
  • parentStyleSheet: 在當前樣式表經過@import導入的狀況下,這個屬性是一個指向導入它的樣式表的指針。
  • title: ownerNode中title屬性的值。
  • type:表示樣式表類型的字符串。對CSS樣式表而言,這個字符串是'text/css'。
  • cssRules:樣式表中包含的樣式規則的集合。IE中相似的是rules屬性。
  • ownerRule:若是樣式表是經過@import導入的,這個屬性就是一個指針,指向表示導入的規則;不然值爲null。
  • deleteRule(index):刪除cssRules集合中指定位置的規則。
  • insertRule(rule, index):向cssRules集合中指定的位置插入rule字符串。

應用於文檔的全部樣式表是經過document.styleSheets集合來表示的。

var sheet = null;

for (var i = 0, len = document.styleSheets.length; i < len; i++) {
    sheet = document.styleSheets[i];
    console.log(sheet.href)
}

複製代碼

元素大小

偏移量

offset dimension,包括元素在屏幕上佔用的全部可見的空間。經過下面四個屬性能夠取得元素的偏移量。

  • offsetHeight
  • offsetWidth
  • offsetLeft
  • offsetTop

其中offsetLeft和offsetTop屬性與包含元素有關,包含元素的引用保存在offsetParent屬性中。offsetParent屬性不必定與parentNode的值相等。例如,元素的offsetParent是做爲其祖先元素的

元素,由於
是在DOM層次中距
最近的一個具備大小的元素。

function getElementOffsetLeft (element) {
   var currentLeft = element.offsetLeft;
   
   var parent = element.offsetParent;
   
   while (parent) {
       currentLeft += parent.offsetLeft;
       parent = parent.offsetParent;
   }
   
   return currentLeft;
}

同理 // top
複製代碼

客戶區大小 client dimension

是指元素內容及其內邊距所佔據的空間大小(content + padding)。

clientWidth屬性是元素內容區寬度加上左右內邊距寬度;clientHeight屬性是元素內容區高度加上上下內邊距高度。

常見用法:肯定瀏覽器視口大小。

function getViewport () {
    if (document.compatMode == 'BackCompat') {
        return {
            width: document.body.clientWidth,
            height: document.body.clientHeight
        }
    } else {
        return {
            width: document.documentElement.clentWidth,
            height: document.documentElement.clientHeight
        }
    }
}
複製代碼

滾動大小(scroll dimension)

指的是包含滾動內容的元素的大小。

4個與滾動大小相關的屬性:

  • scrollHeight: 在沒有滾動條的狀況下,元素內容的總高度。
  • scrollWidth: 在沒有滾動條的狀況下,元素內容的總寬度。
  • scrollLeft:被隱藏在內容區左側的像素數。
  • scrollTop: 被隱藏在內容區域上方的像素數。

由於瀏覽器兼容性的問題,在肯定文檔的總高度時,必須取得scrollWidth/clientWidth和scrollHeight/clientHeight中的最大值,才能保證在跨瀏覽器時獲得精確的結果。

var docHeight = Math.max(document.documentElement.scrollHeight, document.documentElement.clientHeight);

var docWidth = Math.max(document.documentElement.scrollWidth, document.documentElement.clientWidth);
複製代碼

遍歷

DOM2級遍歷和範圍模塊定義了兩個用於輔助完成順序遍歷DOM結構的類型:NodeIterator和TreeWalker

var supportTraversals = document.implementation.hasFeature('Traversal', '2.0');

var supportNodeIterators = (typeof document.createNodeIterator == 'function');

var supportTreeWalker = (typeof document.createTreeWaler == 'function')
複製代碼

NodeIterator

NodeIterator類型是二者中比較簡單的一個,可使用document.createNodeIterator()方法建立它的新實例。這個方法接受下列4個參數。

  • root: 想要做爲搜索起點的樹中的節點。
  • whatToShow:表示要訪問哪些節點的數字代碼
  • filter:是一個NodeFilter對象,或者一個表示應該接受仍是拒絕某種特定的的函數。
  • entityReferenceExpansion:布爾值,表示是否要擴展實體引用。這個參數在HTML頁面中沒有用,由於其中的實體引用不能擴展。

whatToShow參數是一個位掩碼,經過應用一或多個filter來肯定要訪問哪些節點。這個參數的值以常量形式在NodeFilter類型中定義。

  • NodeFilter.SHOW_ALL:顯示全部類型的節點。
  • NodeFilter.SHOW_ELEMENT:顯示元素節點。
  • NodeFilter.SHOW_ATTRIBUTE:顯示特性節點。因爲 DOM 結構緣由,實際上不能使用這個值。
  • NodeFilter.SHOW_TEXT:顯示文本節點。
  • NodeFilter.SHOW_CDATA_SECTION:顯示 CDATA 節點。對 HTML 頁面沒有用。
  • NodeFilter.SHOW_ENTITY_REFERENCE:顯示實體引用節點。對 HTML 頁面沒有用。
  • NodeFilter.SHOW_ENTITYE:顯示實體節點。對 HTML 頁面沒有用。
  • NodeFilter.SHOW_PROCESSING_INSTRUCTION:顯示處理指令節點。對 HTML 頁面沒有用。
  • NodeFilter.SHOW_COMMENT:顯示註釋節點。
  • NodeFilter.SHOW_DOCUMENT:顯示文檔節點。
  • NodeFilter.SHOW_DOCUMENT_TYPE:顯示文檔類型節點。
  • NodeFilter.SHOW_DOCUMENT_FRAGMENT:顯示文檔片斷節點。對 HTML 頁面沒有用。
  • NodeFilter.SHOW_NOTATION:顯示符號節點。對 HTML 頁面沒有用。

除了NodeFilter.SHOW_ALL以外,可使用按位或操做符來組合多個選項:

var whatToShow = NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT;
複製代碼

能夠經過createNodeIterator()方法的filter參數來指定自定義的NodeFilter對象,或者指定一個功能相似節點過濾器(node filter)的函數。

每一個NodeFilter對象只有一個方法,即accept-Node();若是應該訪問給定的節點,該方法返回NodeFilter.FILTER_ACCEPT,若是不該該訪問給定的節點,該方法返回NodeFilter.FILTER_SKIP。因爲NodeFilter是一個抽象的類型,所以不能直接建立它的實例。在必要時,只要建立一個包含acceptNode()方法的對象,而後將這個對象傳入createNodeIterator()中便可。

var filter = {
    acceptNode: function (node) {
        return node.tagName.toLowerCase() == 'p' ?
        NodeFilter.FILTER_ACCEPT :
        NodeFilter.FILTER_SKIP;
    }
};

var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT, filter, false);
複製代碼

第三個參數也能夠是一個與acceptNode()方法相似的函數,以下所示。

var filter = function (node) {
   return node.tagName.toLowerCase() == 'p' ?
   NodeFilter.FILTER_ACCEPT :
   NodeFilter.FILTER_SKIP;
};

var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT, filter, false);
複製代碼

若是不指定過濾器,那麼應該在第三個參數的位置上傳入null。

NodeIterator類型的兩個主要方法是nextNode()和previousNode()。在剛剛建立的NodeIterator對象中,有一個內部指針指向根節點,所以第一次調用nextNode()會返回根節點。

TreeWalker

TreeWalker是NodeIterator的一個更高級的版本。除了包括nextNode()和previousNode()在內的相同的功能以外,這個類型還提供了下列用於在不一樣方向上遍歷DOM結構的方法。

  • parentNode(): 遍歷到當前節點的父節點。
  • firstChild(): 遍歷到當前節點的第一個子節點。
  • lastChild(): 遍歷到當前節點的最後一個子節點
  • nextSibling(): 遍歷到當前節點的下一個同輩節點。
  • previousSibling(): 遍歷到當前節點的上一個同輩節點。

範圍

爲了讓開發人員更方便地控制頁面,「DOM2級遍歷和範圍」模塊定義了「範圍」(range)接口。經過範圍能夠選擇文檔中的一個區域,而沒必要考慮節點的界限。

DOM中的範圍

DOM2級在Document類型中定義了createRange()方法。在兼容DOM的瀏覽器中,這個方法屬於document對象。

var supportsRange = document.implementation.hasFeature('Range', '2.0');

var supportsRange2 = (typeof document.createRange == 'function');
複製代碼

若是瀏覽器支持範圍,那麼就可使用createRange()來建立DOM範圍。

var range = document.createRange();
複製代碼

與節點相似,新建立的範圍也直接與建立它的文檔關聯在一塊兒,不能用於其餘文檔。

IE8及更早版本中的範圍

小結

DOM2級規範定義了一些模塊,用於加強DOM1級

  • DOM2級核心爲不一樣的DOM類型引入了一些與XML命名空間有關的方法。還定義了以編程方式建立Document實例的方法,也支持建立DocumentType對象。
  • DOM2級樣式模塊主要針對操做元素的樣式信息而開發,其特性簡要總結以下:
    • 每一個元素都有一個關聯的style對象,樂意用來肯定和修改行內的樣式。
    • 要肯定某個元素的計算樣式,可使用getComputedStyle()方法。
    • IE不支持getCumputedStyle()方法,但提供了currentStyle()方法。
    • 能夠經過document.styleSheets集合訪問樣式表。
    • 除IE以外的全部瀏覽器都支持針對樣式表的這個接口,IE也爲幾乎全部相應的DOM功能提供了本身的一套屬性和方法。
  • DOM2級遍歷和範圍模塊提供了與DOM結構交互的不一樣方式:
    • 遍歷即便用NodeIterator或TreeWalker對DOM執行深度優先的遍歷。
    • NodeIterator是一個簡單的接口,只容許以一個節點的步幅先後移動。而treeWalker在提供相同功能的同時,還支持在DOM結構的各個方向上移動,包括父節點、同輩節點和子節點等方向。
    • 範圍是選擇DOM結構中特定部分,而後再執行相應操做的一種手段。
    • 使用範圍選區能夠在刪除文檔中某些部分的同時,保持文檔結構的格式良好,或者複製文檔中的相應部分。
    • IE8及更早版本不支持DOM2級遍歷和範圍模塊,但它提供了一個專有的文本範圍對象,能夠用來完成簡單的基於文本的範圍操做。IE9徹底支持DOM遍歷。
相關文章
相關標籤/搜索