《JavaScript高級程序設(shè)計》Chapter 12 DOM 2 和 DOM 3

DOM 變化

  1. 如何確認(rèn)瀏覽器是否支持 DOM 2 和 DOM 3 新增的模塊:

    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')
    
  2. 針對 XML 命名空間的變化

    • 混合命名空間

      <html xmlns="http://www.w3.org/1999/xhtml">
          <head>
              <title> Example XHTML page </title>
          </head>
          <body>
              <svg xmlns="http://www/w3.org/2000/svg" version="1.1" viewBox="0 0 100 100" style="width: 100%; height: 100%">
                  <rect x="0" y="0" width="100" height="100" style="fill: red" />
              </svg>
          </body>
      </html>
      
    • 在 DOM 2 中,Node 類型包含下列特定于命名空間的屬性:

      • localName:不帶命名空間前綴的節(jié)點名稱
      • namespaceURI:命名空間 URI 或者(在未指定的情況下)null
      • prefix:命名空間前綴或者(在未指定的情況下)null
    • DOM 3 引入了下列與命名空間有關(guān)的方法:

      • isDefaultNamespace(namespaceURI):在指定的 namespaceURI是當(dāng)前節(jié)點的默認(rèn)命名空間時返回 true
      • lookupNamespaceURI(prefix):返回給定 prefix 的命名空間。
      • lookupPrefix(namespaceURI):返回給定 namespace 的前綴。
    • DOM 2 的 Document 也發(fā)生了變化,包含了下列與命名空間有關(guān)的方法:

      • createElementNS(namespaceURI, tagName):使用給定的 tagName 創(chuàng)建一個屬于命名空間 namespace 的新元素。
      • createAttributeNS(namespaceURI, attributeName):使用給定的 attributeName 創(chuàng)建一個屬于命名空間 namespaceURI 的新特性。
      • getElementsByTagNameNS(namespaceURI, tagName):返回屬于命名空間 namespaceURItagName 元素的 NodeList 。
    • DOM 2 也為 Element 新增了一些方法:

      • getAttributeNS(namespaceURI, localName):取得屬于命名空間 namespaceURI 且名為 localName 的特性。
      • getAttributeNodeNS(namespaceURI, localName):取得屬于命名空間 namespaceURI 且名為 localName 的特性節(jié)點。
      • getElementsByTagNameNS(namespaceURI, tagName):返回屬于命名空間 namespaceURItagName 元素的 NodeList 。
      • hasAttributeNS(namespaceURI, localName):確定當(dāng)前元素是否有一個名為 localName 的特性,而且該特性的命名空間是 namespaceURI 。
      • removeAttributeNS(namespaceURI, localName):刪除屬于命名空間 namespaceURI 且名為 localName 的特性。
      • setAttributeNS(namespaceURI, qualifiedName, value):設(shè)置屬于命名空間 namespaceURI 且名為 qualifiedName 的特性值為 value 。
      • setAttributeNodeNS(attNode):設(shè)置屬于命名空間 namespaceURI 的特性節(jié)點。
    • NamedNodeMap 類型也新增了下列與命名空間有關(guān)的方法。由于特性是通過 NamedNodeMap 表示的,因此這些方法多數(shù)情況下只針對特性使用:

      • getNamedItemNS(namespaceURI, localName):取得屬于命名空間 namespaceURI 且名為 localName 的項。
      • removeNamedItemNS(namespaceURI, localName):移除屬于命名空間 namespaceURI 且名為 localName 的項。
      • setNamedItemNS(node)?:添加 node 。這個節(jié)點已經(jīng)事先指定了命名空間信息。
  3. 其他方面的變化

    • DocumentType 新增了三個屬性:
      • publicId:文檔類型聲明中的信息段之一(- //W3C//DTD HTML 4.0.1//EN
      • systemId:文檔類型聲明中的信息段之一(http://www.w3.org/TR/html4/strict.dtd
      • internalSubset:訪問包含在文檔類型聲明中的額外定義。
    • Document 類型的變化:
      • 新增 importNode() 用來從一個文檔中獲取一個節(jié)點,然后將其導(dǎo)入到另一個文檔中,使其成為這個文檔結(jié)構(gòu)的一部分。

        • 每個節(jié)點都有一個 ownerDocument 屬性,表示所屬的文檔。如果調(diào)用 appendChild() 時傳入的節(jié)點屬于不同的文檔,會導(dǎo)致錯誤。但是在調(diào)用 importNode() 的時候回返回一個歸當(dāng)前文檔所有的新的節(jié)點。
      • 新增 defaultView 屬性,保存一個指針,指向擁有給定文檔的窗口(或框架)。IE 不支持這個屬性,但有一個等價的屬性名叫 parentWindow。因此,要確定文檔窗口,可以使用以下代碼:

        var parentWindow = document.defaultView || document.parentWindow
        
      • DOM 2 Core 為 document.implementation 對象規(guī)定了兩個新方法:

        • createDocumentType():創(chuàng)建一個新的 DocumentType 節(jié)點。接收三個參數(shù):文檔類型名稱、publicId、systemId。這個方法只在創(chuàng)建新文檔時有用。

          var doctype = document.implementation.createDocumentType("html", "-//W3C//DTD HTML 4.01//EN", "http://www.w3.org/TR/html4/strict.dtd")
          
        • createDocument():創(chuàng)建新文檔。接收三個參數(shù):接受文檔中元素的 namespaceURI、文檔元素的標(biāo)簽名、新文檔的文檔類型。

          var doc = document.implementation.createDocument("http://www.w3.org/1999/xhtml", "html", doctype)
          
      • DOM 2 HTML 為 document.implementation 新增了一個方法:createHTMLDocument() 。這個方法的用途是創(chuàng)建一個完整的 HTML 文檔,包括 html, head, title, body 元素。它只接受一個參數(shù),即新創(chuàng)建的文檔的標(biāo)題(放在 title 里),返回新的 HTML 文檔。只有 Opera 和 Safari 支持這個方法。

    • Node 類型的變化
      • 添加了 isSupported() 方法:用于確定當(dāng)前節(jié)點具有什么能力。接收兩個參數(shù):特性名、特性版本號。如果瀏覽器實現(xiàn)了相應(yīng)特性,而且能夠基于給定節(jié)點執(zhí)行該特性,就返回 true 。

        document.body.isSupported("HTML", "2.0")
        
      • DOM 3 引入了兩個輔助比較節(jié)點的方法:

        • isSameNode():接收一個節(jié)點參數(shù),并在傳入節(jié)點與引用的節(jié)點相同(即同一個對象)時返回 true
        • isEqualNode():接收一個節(jié)點參數(shù),并在傳入節(jié)點與引用的節(jié)點相等(即類型相同)時返回 true。
      • DOM 3 針對為 DOM 節(jié)點添加額外數(shù)據(jù)引入了新方法:

        • setUserData():將數(shù)據(jù)指定給節(jié)點。接收三個參數(shù):要設(shè)置的鍵、實際的數(shù)據(jù)(可以是任何數(shù)據(jù)類型)、處理函數(shù)。
        • getUserData():接收相同的三個參數(shù),獲取數(shù)據(jù)。
        • 傳入 setUserData() 中的處理函數(shù)會在帶有數(shù)據(jù)的節(jié)點被復(fù)制、刪除、重命名或引入一個文檔時調(diào)用。處理函數(shù)接收五個參數(shù):表示操作類型的數(shù)值(1 - 復(fù)制,2 - 導(dǎo)入,3 - 刪除,4 - 重命名),數(shù)據(jù)鍵、數(shù)據(jù)值、源節(jié)點和目標(biāo)節(jié)點。刪除時源節(jié)點是 null ;除復(fù)制外目標(biāo)節(jié)點是 null
    • 框架的變化
      • HTMLFrameElement 和 HTMLIFrameElement 在 DOM 2 中都有了一個新屬性:contentDocument。它包含一個指針,指向表示框架內(nèi)容的文檔對象。在此之前,無法直接通過元素取得這個文檔對象(只能使用 frames 集合)。
        • contentDocument 屬性是 Document 類型的實例,因此可以像使用其他 HTML 文檔一樣使用它,包括所有屬性和方法。IE 8 之前不支持這個屬性,但是支持一個名叫 contentWindow 的屬性。

          var iframe = document.getElementById('myIframe')
          var iframeDoc = iframe.contentDocument || iframe.contentWindow.document
          

樣式

  1. 確定瀏覽器是否支持 DOM 2 級定義的 CSS 能力:

    var supportsDOM2CSS = document.implementation.hasFeature('CSS', '2.0')
    var supportsDOM2CSS2 = document.implementation.hasFeature('CSS2', '2.0')
    
  2. 訪問元素的樣式:

    • 任何支持 style 特性的 HTML 元素在 JavaScript 中都有一個對應(yīng)的 style 屬性。這個 style 對象是 CSSStyleDeclaration 的實例,包含著通過 HTML 的 style 特性指定的所有樣式信息,但不包含與外部樣式表或嵌入樣式表經(jīng)層疊而來的樣式。在 style 特性中指定的任何 CSS 屬性都將表現(xiàn)為這個 style 對象的相應(yīng)屬性。對于使用短劃線的 CSS 屬性名,必須將其轉(zhuǎn)換成駝峰大小寫形式,才能通過 JavaScript 來訪問。
      • 多數(shù)情況下,都可以通過簡單地轉(zhuǎn)換屬性名的格式來實現(xiàn)轉(zhuǎn)換。其中一個不能轉(zhuǎn)換的 CSS 屬性就是 float 。DOM 2 Style 規(guī)范規(guī)定樣式對象上相應(yīng)的屬性名應(yīng)該是 cssFloat,在 IE 上是 styleFloat
      • 在混雜模式下,沒有給出度量單位的值,將默認(rèn)為 px ,但是在標(biāo)準(zhǔn)模式下,這樣的值會被忽略。
    • DOM 2 Style 規(guī)范為 style 對象定義了一些屬性和方法。這些屬性和方法在提供元素的 style 特性值的同時,也可以修改樣式:
      • cssText:訪問 style 特性中的 CSS 代碼(可讀可寫)。
      • length:應(yīng)用給元素的 CSS 屬性的數(shù)量
      • parentRule:表示 CSS 信息的 CSSRule 對象。
      • getPropertyCSSValue(propertyName):返回包含給定屬性值的 CSSValue 對象。
        • CSSValue 包含兩個屬性:cssTextcssValueType ; cssValueType 是一個數(shù)值常量,表示值的類型:0 - 繼承的值,1 - 基本的值,2 - 值列表, 3 - 自定義的值。
      • getPropertyPriority(propertyName):如果給定的屬性使用了 !important 設(shè)置,則返回 important ,否則返回空字符串。
      • getPropertyValue(propertyName):返回給定屬性的字符串值。
      • item(index):返回給定位置的 CSS 屬性的名稱。
      • removeProperty(propertyName):從樣式中刪除給定屬性。
      • setProperty(propertyName, value, priority):將給定屬性設(shè)置為相應(yīng)的值,并加上優(yōu)先權(quán)標(biāo)志( important 或者一個空字符串)。
    • DOM 2 Style 增強(qiáng)了 document.defaultView ,提供了 getComputedStyle() 方法。這個方法接受兩個參數(shù):要取得計算樣式的元素和一個偽元素字符串(例如: :after )。如果不需要偽元素信息可以傳入 null 。這個方法返回一個 CSSStyleDeclaration 對象,其中包含當(dāng)前元素的所有計算后的樣式。
      • 由于瀏覽器解釋綜合( rollup )屬性的方式不同,所以類似 border 這樣的綜合屬性,不會在所有瀏覽器中都有返回值,但是可以通過分別訪問四個邊的屬性(例如 .borderLeftWidth )得到值。
      • IE 不支持 getComputedStyle() 方法,但它有一種類似的概念。在 IE 中,每個具有 style 屬性的元素還有一個 currentStyle 屬性。這個屬性是 CSSStyleDeclaration 的實例,包含當(dāng)前元素全部計算后的樣式。
    • 不能指望某個 CSS 屬性的默認(rèn)值在不同瀏覽器中是相同的,比如 visibility 屬性在有些瀏覽器中默認(rèn)值是 visible ,有些是 inherit。如果你需要元素具有某個特定的默認(rèn)值,應(yīng)該手工在樣式表中指定該值。
  3. 操作樣式表

    • CSSStyleSheet 類型表示的是樣式表,包括通過 <link> 元素包含的樣式表和在 <style> 元素中定義的樣式表。它只表示樣式表,不管這些樣式表在 HTML 中是如何定義的。此外,這個對象是一套只讀接口(有一個屬性例外)。使用下列代碼確認(rèn)瀏覽器是否支持 DOM2 StyleSheet:

      var supportsDOM2StyleSheet = document.implementation.hasFeature('StyleSheets', '2.0')
      
      • CSSStyleSheet 繼承自 StyleSheet ,所以我們可以使用后者作為基礎(chǔ)接口來定義非 CSS 樣式表。從 StyleSheet 接口繼承而來的屬性如下:

        • disabled:表示樣式表是否被禁用。這個屬性是可讀 / 可寫的,將這個屬性設(shè)置為 true 可以禁用樣式表。
        • href:如果樣式表是通過 <link> 包含的,則是樣式表的 URL ,否則,是 null 。
        • media:當(dāng)前樣式表支持的所有媒體類型(MIME Type)的集合。如果集合是空列表,表示樣式表適用于所有媒體。在 IE 中,media 是一個反映 <link><style> 元素 media 特性值的字符串。
        • ownerNode:指向擁有當(dāng)前樣式表的節(jié)點的指針,樣式表可能是在 HTML 中通過 <link><style /> 引入的(在 XML 中可能是通過處理指令引入的)。如果當(dāng)前樣式表是通過其他樣式表通過 @import 導(dǎo)入的,則這個屬性值為 null 。IE 不支持這個屬性。
        • parentStyleSheet:在當(dāng)前樣式表是通過 @import 導(dǎo)入的情況下,這個屬性是一個指向?qū)胨臉邮奖淼闹羔槨?/li>
        • titleownerNodetitle 屬性的值。
        • type:表示樣式表類型的字符串。CSS 是 type/css 。

        以上屬性,除了 disabled 之外,都是只讀的。同時,CSSStyleSheet 還支持下列屬性和方法:

        • cssRules:樣式表中包含的樣式規(guī)則的合集。IE 不支持這個屬性,但是提供了一個類似的 rules 屬性。
        • ownerRules:如果樣式表是通過 @import 導(dǎo)入的,這個屬性就是一個指針,指向表示導(dǎo)入的規(guī)則;否則,值為 null 。IE 不支持這個屬性。
        • deleteRule(index):刪除 cssRules 集合中指定位置的規(guī)則。IE 不支持,但提供了一個類似的 removeRule() 方法。
        • insertRule(rule, index):向 cssRules 集合中指定的位置插入 rule 字符串。IE 不支持,但提供了一個類似的 addRule() 方法。
        for (let i = 0; i < document.styleSheets.length; i++) {
            const sheet = document.styleSheets[i]
            console.log(sheet.href)
        }
        
      • 可以直接通過 <link><style> 元素取得 CSSStyleSheet 對象。DOM 規(guī)定了一個包含 CSSStyleSheet 對象的屬性,叫 sheet 。除了 IE ,其他瀏覽器都支持這個屬性。IE 支持的是 styleSheet 屬性。要想在不同瀏覽器中都能取得樣式表對象,可以使用如下代碼:

        function getStyleSheet (element) {
            return element.sheet || element.styleSheet
        }
        const link = document.getElementsByTagName('link')[0]
        const sheet = getStyleSheet(link)
        
    • CSSRule 對象表示樣式表中的每一條規(guī)則。實際上,CSSRule 是一個供其他多種類繼承的基類型,其中最常見的是 CSSStyleRule 類型,表示樣式表信息(其他規(guī)則還有 @import、@font-face@page@charset ,但這些規(guī)則很少有必要通過腳本來訪問。)CSSStyleRule 對象包含以下屬性:

      • cssText:返回整條規(guī)則對應(yīng)的文本。由于瀏覽器對樣式表的內(nèi)部處理方式不同,返回的文本可能會與樣式表中實際的文本不一樣。Safari 會全部轉(zhuǎn)換為小寫,IE 不支持這個屬性。
        • cssText 包含選擇符文本和圍繞樣式信息的花括號且只讀,style.cssText 只包含樣式信息且可被修改。
      • parentRule:如果當(dāng)前規(guī)則是導(dǎo)入規(guī)則,這個屬性引用的就是導(dǎo)入規(guī)則;否則,這個值為 null 。IE 不支持這個屬性。
      • parentStyleSheet:當(dāng)前規(guī)則所屬的樣式表。IE 不支持這個屬性。
      • ?selectorText:返回當(dāng)前規(guī)則的選擇符文本。由于瀏覽器對樣式表的內(nèi)部處理方式不同,返回的文本可能會與樣式表中實際的文本不一樣。
      • style:一個 CSSStyleDeclaration 對象,可以通過它設(shè)置和取得規(guī)則中特定的樣式值。
      • type:表示規(guī)則類型的常量值。對于樣式規(guī)則,這個值是 1。IE 不支持這個屬性。
      const sheet = document.styleSheets[0]
      const rules = sheet.cssRules || sheet.rules
      const rule = rules[0]
      console.log(rule.cssText)
      console.log(rule.style.cssText)
      
    • DOM 規(guī)定,要向現(xiàn)有樣式表中添加新規(guī)則,需要使用 insertRule() 方法。這個方法接受兩個參數(shù):規(guī)則文本和表示在哪里插入規(guī)則的索引:

      sheet.insertRule('body { background-color: #fff }', 0)
      

      上述語句的插入的規(guī)則將成為樣式表中的第一條規(guī)則(插入到了位置 0)。
      IE 8 及更早的版本支持一個類似的方法,名叫 addRule() ,也接受兩個必選參數(shù):選擇符文本和 CSS 樣式信息;一個可選參數(shù):插入規(guī)則的位置:

      sheet.addRule('body', 'background-color: #fff', 0)
      

      最多只能使用這個方法插入 4095 條樣式規(guī)則。

    • 使用 deleteRule() 刪除規(guī)則。這個方法接受一個參數(shù):要刪除的規(guī)則的位置。IE 支持的類似方法叫 removeRule() ,使用方法相同。

  4. 元素大小

    • DOM 中沒有規(guī)定如何確定頁面中元素的大小,所以下邊的內(nèi)容并不屬于 DOM 2 Style 規(guī)范。IE 最早引入了一些屬性,目前,所有主要瀏覽器都支持這些屬性。

    • 偏移量( offset dimension ):包括元素在屏幕上占用的所有可見空間。元素的可見大小由其高度、寬度決定,包括所有內(nèi)邊距、滾動條和邊框大?。ú话ㄍ膺吘啵?。通過下列四個屬性可以取得元素的偏移量:

      • offsetHeight:元素在垂直方向上占用的空間大小,以像素計。
      • offsetWidth:元素在水平方向占用的空間大小。
      • offsetLeft:元素的左外邊框至包含元素的左內(nèi)邊框之間的像素距離。
      • offsetTop:元素的上外邊框至包含元素的上內(nèi)邊框之間的像素距離。
        • offsetLeftoffsetTop 與包含元素有關(guān)。包含元素的引用保存在 offsetParent 屬性中。這個屬性不一定與 parentNode 的值相等。例如:<td> 元素的 offsetParent 是作為其祖先元素的 <table> 元素,因為 <table> 是在 DOM 層次中距 <td> 最近的一個具有大小的元素。
        • 要想知道某個元素在頁面上的偏移量,將這個元素的 offsetLeftoffsetTop 與其 offsetParent 的相同屬性相加,如此循環(huán)直至根元素,就可以得到一個基本準(zhǔn)確的值。

      所有這些偏移量屬性都是只讀的,并且每次訪問時都要重新計算。為了減少內(nèi)存開銷,我們可以將這些偏移量保存在局部變量中。

    • 客戶區(qū)大?。?client dimension ):元素內(nèi)容及其內(nèi)邊距所占據(jù)的空間大小。包含兩個屬性:

      • clientWidth:元素內(nèi)容區(qū)寬度加上左右內(nèi)邊距寬度。
      • clientHeight:元素內(nèi)容區(qū)高度加上上下內(nèi)邊距高度。

      確定瀏覽器視口大?。?/p>

      function getViewport () {
          if (document.compatMode == 'BackCompat') { // 是否運行在混雜模式
              return {
                  width: document.body.clientWidth,
                  height: document.body.clientHeight
              }
          } else {
              return {
                  width: document.documentElement.clientWidth,
                  height: document.documentElement.clientHeight
              }
          }
      }
      

      客戶區(qū)大小也是只讀的,也需要重新計算。

    • 滾動大?。?scroll dimension ):包含滾動內(nèi)容的元素的大小。包含以下四個屬性:

      • scrollHeight:在沒有滾動條的情況下,元素內(nèi)容的總高度。
      • ?scrollWidth:在沒有滾動條的情況下,元素內(nèi)容的總寬度。
      • scrollLeft:被隱藏在內(nèi)容區(qū)域左側(cè)的像素數(shù)。通過設(shè)置該屬性可以改變元素的滾動位置。
      • scrollTop:被隱藏在內(nèi)容區(qū)域上方的像素數(shù)。通過設(shè)置該屬性可以改變元素的滾動位置。
        由于一些兼容性差異,在確定文檔的總高度時(包括基于視口的最小高度時),必須取得 scrollWidth / clientWidthscrollHeight / clientHeight 中的最大值,才能保證在跨瀏覽器的環(huán)境下得到精確的結(jié)果。對于運行在混雜模式下的 IE ,要使用 document.body 代替 document.documentElement 。
    • 所有的瀏覽器都提供了 getBoundingClientRect() 方法用來確定元素大小。這個方法會返回一個矩形對象,包含四個屬性:lefttop、right、bottom。這些屬性給出了元素在頁面中相對于視口的位置。在 IE 及更早版本的瀏覽器中,文檔左上角的起點坐標(biāo)是 (2, 2) 而其他瀏覽器是 (0, 0) 。所以需要檢查一下位于 (0, 0) 處元素的位置:

      function getBoundingClientRect (element) {
          if (typeof arguments.callee.offset !== 'number') {
              var scrollTop = document.documentElement.scrollTop
              var temp = document.createElement('div')
              temp.style.cssText = 'position: absolute; left: 0; top: 0;'
              document.body.appendChild(temp)
              arguments.callee.offset = - temp.getBoundingClientRect().top - scrollTop
              document.body.removeChild(temp)
              temp = null
          }
          var rect = element.getBoundingClientRect()
          var offset = arguments.callee.offset
          return {
              left: rect.left + offset
              right: rect.right + offset
              top: rect.top + offset
              bottom: rect.bottom + offset
      

      Poly Fill: Custom getBoundingClientRect() method [詳見書 P326]

遍歷

  1. DOM 2 Traversal 定義了兩個用于輔助完成順序遍歷 DOM 結(jié)構(gòu)的類型:NodeIterator 和 TreeWalker 。這兩個屬性能夠基于給定的起點對 DOM 結(jié)構(gòu)進(jìn)行深度優(yōu)先遍歷操作。IE 不支持 DOM 遍歷。使用下列代碼檢測:

    var supportsTraversals = document.implementation.hasFeature('Traversal', '2.0')
    var supportsNodeIterator = (typeof document.createNodeIterator === 'function')
    var supportsTreeWalker = (typeof document.createTreeWalker === 'function')
    
  2. NodeIterator 類型是兩者中比較簡單的一個,可以使用 document.createNodeIterator() 方法創(chuàng)建它的新實例。它接收以下四個參數(shù):

    • root:想要作為搜索起點的樹中的節(jié)點。
    • whatToShow:表示要訪問哪些節(jié)點的數(shù)字代碼。
      • 它的參數(shù)是一個位掩碼,通過應(yīng)用一個或多個過濾器( filter )來確定要訪問哪些節(jié)點。這個參數(shù)的值以常量形式在 NodeFilter 類型中定義,如下所示:

        • NodeFilter.SHOW_ALL:顯示所有類型的節(jié)點。
        • NodeFilter.SHOW_ELEMENT:顯示元素節(jié)點。
        • NodeFilter.SHOW_ATTRIBUTE:顯示特性節(jié)點。由于 DOM 結(jié)構(gòu)原因,實際上不能使用這個值。
        • NodeFilter.SHOW_TEXT:顯示文本節(jié)點。
        • NodeFilter.SHOW_CDATA_SECTION:顯示 CDATA 節(jié)點。對 HTML 頁面沒有作用。
        • NodeFilter.SHOW_ENTITY_REFERENCE:顯示實體引用節(jié)點。對 HTML 頁面沒有作用。
        • NodeFilter.SHOW_ENTITY:顯示實體節(jié)點。對 HTML 頁面沒有作用。
        • NodeFilter.SHOW_PROCESSING_INSTRUCTION:顯示處理指令節(jié)點。對 HTML 頁面沒有作用。
        • NodeFilter.SHOW_COMMENT:顯示注釋節(jié)點。
        • NodeFilter.SHOW_DOCUMENT:顯示文檔節(jié)點。
        • NodeFilter.SHOW_DOCUMENT_TYPE:顯示文檔類型節(jié)點。
        • NodeFilter.SHOW_DOCUMENT_FRAGMENT:顯示文檔片段節(jié)點。對 HTML 頁面沒有作用。
        • NodeFilter.SHOW_NOTATION:顯示符號節(jié)點。對 HTML 頁面沒有作用。

        除了 SHOW_ALL 之外,可以用 | 運算符組合多個選項。

    • filter:一個 NodeFilter 對象,或者一個表示應(yīng)該接受還是拒絕某種特定節(jié)點的函數(shù)。
      • 每個 FilterNode 對象只有一個方法,即 acceptNode() 。如果應(yīng)該訪問給定的節(jié)點,該方法返回 NodeFilter.FILTER_ACCEPT ,如果不應(yīng)該則返回 NodeFilter.FILTER_SKIP 。這是一個抽象類型,不能直接創(chuàng)建它的實例。在必要時,只要創(chuàng)建一個包含 acceptNode() 方法的對象,然后將這個對象傳入 createNodeIterator() 中即可。
    • entityReferenceExpansion:布爾值,表示是否要擴(kuò)展實體引用。這個參數(shù)在 HTML 頁面中沒有用,因為其中的實體引用不能擴(kuò)展。

    NodeIterator 類型的兩個主要方法:

    • nextNode():向后前進(jìn)一步,當(dāng)遍歷到最后一個節(jié)點時,返回 null 。
    • previousNode():向前倒退一步,當(dāng)遍歷到根節(jié)點時,返回 null 。

    例子:返回遍歷中遇到的 <li> 元素

    var div = document.getElementById('div1')
    var filter = function (node) {
        return node.tagName.toLowerCase() === 'li' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP
    }
    var iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT, filter, false)
    var node = iterator.nextNode()
    while(node !== null) {
        console.log(node.tagName)
        node = iterator.nextNode()
    }
    
  3. TreeWalker 是 NodeIterator 的一個更高級的版本。除了包括 nextNode()previousNode() 在內(nèi)的相同功能之外,這個類型還提供了下列用于在不同方向上遍歷 DOM 結(jié)構(gòu)的方法。

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

    創(chuàng)建 TreeWalker 對象要使用 document.createTreeWalker() 方法,這個方法接受四個參數(shù),與 document.createNodeIterator 相同。

    • filter 的返回值,除了 FILTER_ACCEPTFILTER_SKIP 之外,還可以使用 FILTER_REJECT ,在 NodeIterator 中,NodeFilter.FILTER_SKIPNodeFilter.FILTER_REJECT 作用相同:跳過指定節(jié)點。但在 TreeWalker 中,FILTER_SKIP 會跳過相應(yīng)節(jié)點繼續(xù)前進(jìn)到子樹中的下一個節(jié)點,而 FILTER_REJECT 會跳過相應(yīng)節(jié)點及該節(jié)點的整個子樹。

范圍

  1. DOM 2 Traversal & Range 模塊定義了范圍( range )接口。通過范圍可以選擇文檔中的一個區(qū)域,而不必考慮節(jié)點的界限(選擇在后臺完成,對用戶是不可見的。)IE 實現(xiàn)范圍特性的方式不同。

  2. DOM 2 在 Document 類型中定義了 createRange() 方法。在兼容 DOM 的瀏覽器中,這個方法屬于 document 對象。檢測方法:

    var supportsRange = document.implementation.hasFeature('Range', '2.0')
    var alsoSupportsRange = (typeof document.createRange === 'function')
    
  3. 可以使用 document.createRange() 創(chuàng)建一個 Range 類型的實例。該實例包含以下屬性,他們提供了當(dāng)前范圍在文檔中的位置信息:

    • startContainer:包含范圍起點的節(jié)點(即選中區(qū)第一個節(jié)點的父節(jié)點)
    • startOffset:范圍在 startContainer 中起點的偏移量。如果 startContainer 是文本節(jié)點、注釋節(jié)點或 CDATA 節(jié)點,那么 startOffset 就是范圍起點之前跳過的字符數(shù)量,否則,就是范圍中第一個子節(jié)點的索引。
    • endContainer:包含范圍終點的節(jié)點(即選區(qū)中最后一個節(jié)點的父節(jié)點)。
    • endOffset:范圍在 endContainer 中終點的偏移量(與 startOffset 遵循相同的取值規(guī)則)。
    • commonAncestorContainerstartContainerendContainer 共同的祖先節(jié)點在文檔樹中位置最深的那個。
  4. 用 DOM 范圍實現(xiàn)簡單選擇:selectNode()selectNodeContents() 。它們都接收一個參數(shù),即一個 DOM 節(jié)點。然后使用該節(jié)點中的信息來填充范圍。其中,selectNode() 方法選擇整個節(jié)點,包括子節(jié)點;selectNodeContents() 只選擇節(jié)點的子節(jié)點。

    var range = document.createRange()
    range.selectNode(document.getElementById('test')
    

    為了更精細(xì)的控制將哪些節(jié)點包含在范圍中,還可以使用下列方法:

    • setStartBefore(refNode):將范圍起點設(shè)置在 refNode 之前,即 refNode 是范圍選區(qū)中的第一個子節(jié)點。
    • setStartAfter(refNode):將范圍起點設(shè)置在 refNode 之后,即 refNode 的下一個同輩節(jié)點是范圍選區(qū)中的第一個子節(jié)點。
    • ?setEndBefore(refNode):將范圍終點設(shè)置在 refNode 之前,即 refNode 的上一個同輩節(jié)點是范圍選區(qū)中的最后一個子節(jié)點。
    • ?setEndAfter(refNode):將范圍終點設(shè)置在 refNode 之后,即 refNode 是范圍選區(qū)中的最后一個子節(jié)點。
  5. 用 DOM 范圍實現(xiàn)復(fù)雜選擇:setStart()setEnd()。這兩個方法都接受兩個參數(shù):參照節(jié)點和偏移量,分別對應(yīng) startContainer / endContainerstartOffset / endOffset 。

  6. 操作 DOM 范圍中的內(nèi)容:創(chuàng)建范圍時,內(nèi)部會為這個范圍創(chuàng)建一個文檔片段,范圍所屬的全部節(jié)點都被添加到了這個文檔片段中。范圍會自動完善 DOM 結(jié)構(gòu),變成一個有效的 DOM 。于是,就可以使用下列方法進(jìn)行操作了:

    • deleteContents:從文檔中刪除范圍所包含的內(nèi)容。
    • extractContents:從文檔中移除范圍選區(qū)(返回范圍的文檔片段)。
    • cloneContents:返回范圍中節(jié)點的副本作為文檔片段。
  7. 插入 DOM 范圍中的內(nèi)容:insertNode()

  8. 折疊 DOM 范圍:collapse()

  9. 比較 DOM 范圍:compareBoundaryPoints() 比較是否有公共邊界(起點或終點)

  10. 復(fù)制 DOM 范圍:range.cloneRange()

  11. 清理 DOM 范圍:

    range.detach()
    range = null
    
  12. IE 8 及更早版本的范圍
    [詳見書 P340]

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

推薦閱讀更多精彩內(nèi)容