前端重新學習(5)DOM與DOM2、DOM3區別以及DOM2新特性

------------摘抄自他人筆記(http://itbilu.com/javascript/js/Vyxodm_1g.html、https://blog.csdn.net/pxy_lele/article/details/49755071)

感謝分享----------------------

目錄

DOM0、DOM1、DOM2、DOM3的區別

DOM0

DOM0與DHTML

DOM1的出現

DOM2與DOM3

DOM2總結

DOM2新增模塊-樣式

 1. DOM樣式屬性和方法

2. 計算的樣式

操作樣式表 

 

DOM2新增模塊-遍歷

NodeIterator 

TreeWalker

DOM2新增模塊-範圍

1. 用 DOM範圍實現簡單選擇 

2. 用 DOM範圍實現複雜選擇 

3. 操作 DOM範圍中的內容 

4. 插入 DOM範圍中的內容 

5. 摺疊 DOM範圍 

6. 比較 DOM範圍 

7. 複製 DOM範圍 

8. 清理 DOM範圍 

  IE8及更早版本中的範圍 

1. 用 IE範圍實現簡單的選擇 

2. 使用 IE範圍實現複雜的選擇 

3. 操作 IE範圍中的內容 

4. 摺疊 IE範圍 

5. 比較 IE範圍 

6. 複製 IE範圍 


 

DOM0、DOM1、DOM2、DOM3的區別

DOM0

JavaScript在早期版本中提供了查詢和操作Web文檔的內容API(如:圖像和表單),在JavaScript中定義了定義了'images''forms'等,因此我們可以像下這樣訪問第一張圖片或名爲“user”的表單:

document.images[0]
document.forms['user']

這實際上是未形成標準的試驗性質的初級階段的DOM,現在習慣上被稱爲DOM0,即:第0級DOM。由於DOM0W3C進行標準備化之前出現,還處於未形成標準的初期階段,這時NetscapeMicrosoft各自推出自己的第四代瀏覽器,自此DOM開始出各種問題。

DOM0與DHTML

Netscape Navigator 4IE4分別發佈於1997年的6月和10月,這兩種瀏覽器都大幅擴展了DOM,使JavaScript的功能大大增加,而此時也開始出現一個新名詞:DHTML

DHTMLDynamic HTML(動態HTML)的簡稱。DHTML並不是一項新技術,而是將HTML、CSS、JavaScript技術組合的一種描述。即:

  • 利用HTML把網頁標記爲各種元素
  • 利用CSS設置元素樣式及其顯示位置
  • 利用JavaScript操控頁面元素和樣式

利用DHTML,看起來可以很容易的控制頁面元素,並實現一此原本很複雜的效果(如:通過改變元素位置實現動畫)。但事實並非如此,因爲沒有規範和標準,兩種瀏覽器對相同功能的實現確完全不一樣。爲了保持程序的兼容性,程序員必須寫一些探查代碼以檢測JavaScript是運行於哪種瀏覽器之下,並提供與之對應的腳本。JavaScript陷入了前所未有的混亂,DHTML也因此在人們心中留下了很差的印象。

DOM1的出現

在瀏覽器廠商進行瀏覽器大站的同時,W3C結合大家的優點推出了一個標準化的DOM,並於1998年10月完成了第一級 DOM,即:DOM1W3CDOM定義爲一個與平臺和編程語言無關的接口,通過這個接口程序和腳本可以動態的訪問和修改文檔的內容、結構和樣式。

DOM1級主要定義了HTML和XML文檔的底層結構。在DOM1中,DOM由兩個模塊組成:DOM Core(DOM核心)和DOM HTML。其中,DOM Core規定了基於XML的文檔結構標準,通過這個標準簡化了對文檔中任意部分的訪問和操作。DOM HTML則在DOM核心的基礎上加以擴展,添加了針對HTML的對象和方法,如:JavaScript中的Document對象

DOM2與DOM3

DOM1的基礎上DOM2DOM3引入了更多的交互能力,也支持了更高級的XML特性。DOM2DOM3將DOM分爲更多具有聯繫的模塊。DOM2級在原來DOM的基礎上又擴充了鼠標、用戶界面事件、範圍、遍歷等細分模塊,而且通過對象接口增加了對CSS的支持。DOM1級中的DOM核心模塊也經過擴展開始支持XML命名空間。DOM2中引入了下列模塊,在模塊包含了衆多新類型和新接口:

  • DOM視圖(DOM Views):定義了跟蹤不同文檔視圖的接口
  • DOM事件(DOM Events):定義了事件和事件處理的接口
  • DOM樣式(DOM Style):定義了基於CSS爲元素應用樣式的接口
  • DOM遍歷和範圍(DOM Traversal and Range):定義了遍歷和操作文檔樹的接口

DOM3進一步擴展了DOM,DOM3中引入了以下模塊:

  • DOM加載和保存模塊(DOM Load and Save):引入了以統一方式加載和保存文檔的方法
  • DOM驗證模塊(DOM Validation):定義了驗證文檔的方法
  • DOM核心的擴展(DOM Style):支持XML 1.0規範,涉及XML Infoset、XPath和XML Base

DOM2總結

DOM2級規範定義了一些模塊,用於增強 DOM1級。“DOM2級核心”爲不同的 DOM類型引入了 一些與 XML命名空間有關的方法。這些變化只在使用 XML或 XHTML文檔時纔有用;對於 HTML文 檔沒有實際意義。除了與 XML 命名空間有關的方法外, “DOM2 級核心”還定義了以編程方式創建 Document 實例的方法,也支持了創建 DocumentType 對象。 

“DOM2級樣式”模塊主要針對操作元素的樣式信息而開發,其特性簡要總結如下。 

  • 每個元素都有一個關聯的 style 對象,可以用來確定和修改行內的樣式。 
  • 要確定某個元素的計算樣式(包括應用給它的所有 CSS規則),可以使用 getComputedStyle() 方法。 
  • IE不支持getComputedStyle()方法,但爲所有元素都提供了能夠返回相同信息 currentStyle 屬性。 
  • 可以通過 document.styleSheets 集合訪問樣式表。 
  • 除 IE之外的所有瀏覽器都支持針對樣式表的這個接口,IE也爲幾乎所有相應的 DOM功能提供 了自己的一套屬性和方法。

“DOM2級遍歷和範圍”模塊提供了與 DOM結構交互的不同方式,簡要總結如下。 

  • 遍歷即使用 NodeIterator 或 TreeWalker 對 DOM執行深度優先的遍歷。 
  • NodeIterator 是一個簡單的接口,只允許以一個節點的步幅前後移動。而 TreeWalker 在提 供相同功能的同時,還支持在 DOM結構的各個方向上移動,包括父節點、同輩節點和子節點等 方向。 
  • 範圍是選擇 DOM結構中特定部分,然後再執行相應操作的一種手段。 
  • 使用範圍選區可以在刪除文檔中某些部分的同時,保持文檔結構的格式良好,或者複製文檔中 的相應部分。 
  • IE8及更早版本不支持“DOM2級遍歷和範圍”模塊,但它提供了一個專有的文本範圍對象,可 以用來完成簡單的基於文本的範圍操作。IE9完全支持 DOM遍歷。 

DOM2新增模塊-樣式

在 HTML中定義樣式的方式有 3種:通過<link/>元素包含外部樣式表文件、使用<style/>元素 定義嵌入式樣式,以及使用 style 特性定義針對特定元素的樣式。“DOM2級樣式”模塊圍繞這 3種應用 樣式的機制提供了一套 API。要確定瀏覽器是否支持 DOM2級定義的 CSS能力,可以使用下列代碼。 

var supportsDOM2CSS = document.implementation.hasFeature("CSS", "2.0"); 
var supportsDOM2CSS2 = document.implementation.hasFeature("CSS2", "2.0"); 

 在 style 特性中指定的任何 CSS屬性都將表現爲這個 style 對象的相應屬性。對於使用短劃線(分隔不同的詞彙,例如 background-image)的 CSS屬性 名,必須將其轉換成駝峯大小寫形式,才能通過 JavaScript來訪問。下表列出了幾個常見的 CSS屬性及 其在 style 對象中對應的屬性名。 
 


注:float 是 JavaScript中的保留字,因此不能用作屬性名

“DOM2級樣式”規範規定 樣式對象上相應的屬性名應該是 cssFloat;Firefox、Safari、Opera和 Chrome都支持這個屬性,而 IE 支持的則是 styleFloat。

 

只要取得一個有效的DOM元素的引用,就可以隨時使用JavaScript爲其設置樣式。

var myDiv = document.getElementById("myDiv"); 
 
//設置背景顏色
 myDiv.style.backgroundColor = "red"; 
 
//改變大小 
myDiv.style.width = "100px"; myDiv.style.height = "200px"; 
 
//指定邊框 
myDiv.style.border = "1px solid black";
// 在以這種方式改變樣式時,元素的外觀會自動被更新。 

在標準模式下,所有度量值都必須指定一個度量單位。在混雜模式下,可以將 style.width 設置爲"20",瀏覽器會假設它是"20px";但在標準模式下,將 style.width 設置爲"20"會導致被忽略——因爲沒有度量單位。在實踐中,最好始 終都指定度量單位 

 1. DOM樣式屬性和方法

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

  • cssText:如前所述,通過它能夠訪問到 style 特性中的 CSS代碼。 
  • length:應用給元素的 CSS屬性的數量。 
  • parentRule:表示 CSS信息的 CSSRule 對象。本節後面將討論 CSSRule 類型。 
  • getPropertyCSSValue(propertyName):返回包含給定屬性值的 CSSValue 對象。 
  • getPropertyPriority(propertyName):如果給定的屬性使用了!important 設置,則返回 "important";否則,返回空字符串。  getPropertyValue(propertyName):返回給定屬性的字符串值。 
  • item(index):返回給定位置的 CSS屬性的名稱。 
  • removeProperty(propertyName):從樣式中刪除給定屬性。 
  • setProperty(propertyName,value,priority):將給定屬性設置爲相應的值,並加上優先 權標誌("important"或者一個空字符串)

通過cssText屬性可以訪問style特性中的CSS代碼。

在讀取模式下,cssText返回瀏覽器對style 特性中 CSS代碼的內部表示。

在寫入模式下,賦給 cssText 的值會重寫整個 style 特性的值;也就是 說,以前通過 style 特性指定的樣式信息都將丟失。例如,如果通過 style 特性爲元素設置了邊框, 然後再以不包含邊框的規則重寫 cssText,那麼就會抹去元素上的邊框。js的優先級高於css。

2. 計算的樣式

雖然 style 對象能夠提供支持 style 特性的任何元素的樣式信息,但它不包含那些從其他樣式表 層疊而來並影響到當前元素的樣式信息。“DOM2 級樣式”增強了 document.defaultView,提供了 getComputedStyle()方法。這個方法接受兩個參數:要取得計算樣式的元素和一個僞元素字符串(例 如":after")。

如果不需要僞元素信息,第二個參數可以是 null。getComputedStyle()方法返回一 個 CSSStyleDeclaration 對象(與 style 屬性的類型相同),其中包含當前元素的所有計算的樣式。

<!--下面這個 HTML頁面爲例。-->
 <!DOCTYPE html> 
<html> 
    <head>     
        <title>Computed Styles Example</title>     
    <style type="text/css">        
     #myDiv {             
                background-color: blue;             
                width: 100px;             
                height: 200px;         
            }    
     </style> 
    </head> 
<body>   
  
<div id="myDiv" style="background-color: red; border: 1px solid black"></div> 

</body> 
</html> 

應用給這個例子中<div>元素的樣式一方面來自嵌入式樣式表(<style>元素中的樣式),另一方 面來自其 style 特性。但是,style 特性中設置了 backgroundColor 和 border,沒有設置 width 和 height,後者是通過樣式表規則應用的。以下代碼可以取得這個元素計算後的樣式。 

var myDiv = document.getElementById("myDiv"); 
var computedStyle = document.defaultView.getComputedStyle(myDiv, null); 
alert(computedStyle.backgroundColor);  // "red" 
alert(computedStyle.width);    // "100px" 
alert(computedStyle.height);    // "200px" 
alert(computedStyle.border);    // 在某些瀏覽器中是"1px solid black" 

 不能指望某個 CSS 屬性的默認值在不同瀏覽器中是相同 的。如果你需要元素具有某個特定的默認值,應該手工在樣式表中指定該值。 

 

操作樣式表 

使用下面的代碼可以確定瀏覽器是否支持 DOM2級樣式表。 

var supportsDOM2StyleSheets =  
            document.implementation.hasFeature("StyleSheets", "2.0"); 

 CSSStyleSheet 繼承自 StyleSheet,後者可以作爲一個基礎接口來定義非 CSS 樣式表。從 StyleSheet 接口繼承而來的屬性如下。  disabled:表示樣式表是否被禁用的布爾值。這個屬性是可讀/寫的,將這個值設置爲 true 可 以禁用樣式表。 

 

 

 

 

 應用於文檔的所有樣式表是通過 document.styleSheets 集合來表示的。通過這個集合的 length 屬性可以獲知文檔中樣式表的數量,而通過方括號語法或 item()方法可以訪問每一個樣式表。來看一個 例子。 

 

  • href:如果樣式表是通過<link>包含的,則是樣式表的 URL;否則,是 null。 
  • media:當前樣式表支持的所有媒體類型的集合。與所有 DOM 集合一樣,這個集合也有一個 length 屬性和一個 item()方法。也可以使用方括號語法取得集合中特定的項。如果集合是空 列表,表示樣式表適用於所有媒體。在 IE中,media 是一個反映<link>和<style>元素 media 特性值的字符串。 
  • ownerNode:指向擁有當前樣式表的節點的指針,樣式表可能是在 HTML 中通過<link>或 <style/>引入的(在 XML中可能是通過處理指令引入的)。如果當前樣式表是其他樣式表通過 @import 導入的,則這個屬性值爲 null。IE不支持這個屬性。 
  • parentStyleSheet:在當前樣式表是通過@import 導入的情況下,這個屬性是一個指向導入 它的樣式表的指針。 
  • title:ownerNode 中 title 屬性的值。  type:表示樣式表類型的字符串。對 CSS樣式表而言,這個字符串是"type/css"。 除了 disabled 屬性之外,其他屬性都是隻讀的。在支持以上所有這些屬性的基礎上, CSSStyleSheet 類型還支持下列屬性和方法: 
  • cssRules:樣式表中包含的樣式規則的集合。IE不支持這個屬性,但有一個類似的 rules 屬性。
  • ownerRule:如果樣式表是通過@import 導入的,這個屬性就是一個指針,指向表示導入的規 則;否則,值爲 null。IE不支持這個屬性。 deleteRule(index):刪除 cssRules 集合中指定位置的規則。IE 不支持這個方法,但支持 一個類似的 removeRule()方法。 
  • insertRule(rule,index):向 cssRules 集合中指定的位置插入 rule 字符串。IE不支持這 個方法,但支持一個類似的 addRule()方法。 
var sheet = null; 
    for (var i=0, len=document.styleSheets.length; i < len; i++){ 
           sheet = document.styleSheets[i];     
            alert(sheet.href); 
    } 
 

 以上代碼可以輸出文檔中使用的每一個樣式表的 href 屬性(<style>元素包含的樣式表沒有 href 屬性) 。 不同瀏覽器的 document.styleSheets 返回的樣式表也不同。所有瀏覽器都會包含<style>元素 和 rel 特性被設置爲"stylesheet"的<link>元素引入的樣式表。IE和 Opera也包含 rel 特性被設置 爲"alternate stylesheet"的<link>元素引入的樣式表。 

DOM2新增模塊-遍歷

“DOM2級遍歷和範圍”模塊定義了兩個用於輔助完成順序遍歷 DOM結構的類型:NodeIterator 和 TreeWalker。這兩個類型能夠基於給定的起點對 DOM結構執行深度優先(depth-first)的遍歷操作。 在與 DOM兼容的瀏覽器中(Firefox 1及更高版本、Safari 1.3及更高版本、Opera 7.6及更高版本、Chrome 0.2及更高版本),都可以訪問到這些類型的對象。IE不支持 DOM遍歷。使用下列代碼可以檢測瀏覽器 對 DOM2級遍歷能力的支持情況。 

var supportsTraversals = document.implementation.hasFeature("Traversal", "2.0");
 var supportsNodeIterator = (typeof document.createNodeIterator == "function"); 
var supportsTreeWalker = (typeof document.createTreeWalker == "function"); 

 DOM 遍歷是深度優先的 DOM 結構遍歷,也就是說,移動的方向至少有兩個(取決 於使用的遍歷類型)。遍歷以給定節點爲根,不可能向上超出 DOM樹的根節點。

從 document 開始依序向前,訪問的第一個節點是 document,訪問的後一個節點是包含 "world!"的文本節點。從文檔後的文本節點開始,遍歷可以反向移動到 DOM 樹的頂端。此時,訪 問的第一個節點是包含"Hello"的文本節點,訪問的後一個節點是 document 節點。NodeIterator 和 TreeWalker 都以這種方式執行遍歷。

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; 
 

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Page Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
   
  
</head>
<body>
    <div id="div1">
        <p>
            <b>Hello</b> world!</p>
        <ul>
            <li>List item 1</li>
            <li>List item 2</li>
            <li>List item 3</li>
        </ul>
    </div>
</body>
<script src="./static/main.js"></script>
</html>
/*main.js*/
var div = document.getElementById("div1"); 
//
var filter = function (node) {
     return node.tagName.toLowerCase() == "li" ? 
     NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP; 
    };
//filter是過濾條件,下面iterator中filter改成null,則表示對輸出沒有輸出限制
var iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT, 
    filter, false); 
var node = iterator.nextNode(); 
    while (node !== null) {     
        document.write (node.tagName+"   ");        //輸出標籤名     
        node = iterator.nextNode(); 
    }

 由於 nextNode()和 previousNode()方法都基於 NodeIterator 在 DOM結構中的內部指針工 作,所以 DOM結構的變化會反映在遍歷的結果中。 

 

TreeWalker

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

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

創建 TreeWalker 對象要使用 document.createTreeWalker()方法,這個方法接受的 4個參數 與 document.createNodeIterator()方法相同作爲遍歷起點的根節點、要顯示的節點類型、過濾 器和一個表示是否擴展實體引用的布爾值。由於這兩個創建方法很相似,所以很容易用 TreeWalker 來代替 NodeIterator,如下面的例子所示。 
 

var div = document.getElementById("div1"); 
var filter = function(node){     /*條件建立*/
    return node.tagName.toLowerCase() == "li"?          
        NodeFilter.FILTER_ACCEPT :          
    NodeFilter.FILTER_SKIP; 
}; 
 /*,filter 可以返回的值有所不同。除了 NodeFilter.FILTER_ACCEPT 和 
NodeFilter. FILTER_SKIP 之外,還可以使用 NodeFilter.FILTER_REJECT。
在使用 NodeIterator 對象時, NodeFilter.FILTER_SKIP 與 NodeFilter.FILTER_REJECT 的作用相同:跳過指定的節點。
但在使 用 TreeWalker 對象時,NodeFilter.FILTER_SKIP 會跳過相應節點繼續前進到子樹中的下一個節
點, 而 NodeFilter.FILTER_REJECT 則會跳過相應節點及該節點的整個子樹。例如,將前面例子中的 
NodeFilter.FILTER_SKIP 修改成 NodeFilter.FILTER_REJECT,結果就是不會訪問任何節點。這是 因爲
第一個返回的節點是<div>,它的標籤名不是"li",於是就會返回 NodeFilter.FILTER_REJECT, 這意味着
遍歷會跳過整個子樹。在這個例子中,<div>元素是遍歷的根節點,於是結果就會停止遍歷。 */
var walker= document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT,                 filter, false); 
 
var node = iterator.nextNode(); 
while (node !== null) {     
    alert(node.tagName);        //輸出標籤名     
    node = iterator.nextNode(); 
}

 TreeWalker 真正強大的地方在於能夠在 DOM結構中沿任何方向移動。使用 TreeWalker 遍歷 DOM樹,即使不定義過濾器,也可以取得所有<li>元素,如下面的代碼所示

var div = document.getElementById("div1"); 
var walker = document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT, null, false); 
 
walker.firstChild();            
//轉到<p> 
walker.nextSibling();         
// 轉到<ul> 
var node = walker.firstChild();        
//轉到第一個<li> 
while (node !== null) {     
    alert(node.tagName);     
    node = walker.nextSibling(); 
}  
 

 TreeWalker 類型還有一個屬性,名叫 currentNode,表示任何遍歷方法在上一次遍歷中返回的 節點。通過設置這個屬性也可以修改遍歷繼續進行的起點

var node = walker.nextNode(); 
alert(node === walker.currentNode);     //true 
walker.currentNode = document.body;     //修改起點 
/* 與 NodeIterator 相比,TreeWalker 類型在遍歷 DOM時擁有更大的靈活性。
由於 IE中沒有對 應的類型和方法,所以使用遍歷的跨瀏覽器解決方案非常少見*/

DOM2新增模塊-範圍

“DOM2級遍歷和範圍”模塊定義了“範圍”(range)接口。

通過範圍可以選擇文檔中的一個區域,而不必考慮節點的界限(選擇在後臺完成,對用戶是不可見的) 。 在常規的 DOM操作不能更有效地修改文檔時,使用範圍往往可以達到目的。Firefox、Opera、Safari和 Chrome都支持 DOM範圍。IE以專有方式實現了自己的範圍特性。 

DOM2級在 Document 類型中定義了 createRange()方法。在兼容 DOM的瀏覽器中,這個方法 屬於 document 對象。使用 hasFeature()或者直接檢測該方法,都可以確定瀏覽器是否支持範圍。 

var supportsRange = document.implementation.hasFeature("Range", "2.0"); 
var alsoSupportsRange = (typeof document.createRange == "function"); 
 

如果瀏覽器支持範圍,那麼就可以使用 createRange()來創建 DOM範圍,如下所示: 

var range = document.createRange(); 

與節點類似,新創建的範圍也直接與創建它的文檔關聯在一起,不能用於其他文檔。創建了範圍之 後,接下來就可以使用它在後臺選擇文檔中的特定部分。而創建範圍並設置了其位置之後,還可以針對 範圍的內容執行很多種操作,從而實現對底層 DOM樹的更精細的控制。

每個範圍由一個 Range 類型的實例表示,這個實例擁有很多屬性和方法。下列屬性提供了當前範 圍在文檔中的位置信息。

 

  • startContainer:包含範圍起點的節點(即選區中第一個節點的父節點)。 
  • startOffset:範圍在 startContainer 中起點的偏移量。如果 startContainer 是文本節 點、註釋節點或 CDATA節點,那麼 startOffset 就是範圍起點之前跳過的字符數量。否則, startOffset 就是範圍中第一個子節點的索引。 
  • endContainer:包含範圍終點的節點(即選區中後一個節點的父節點)。 
  • endOffset:範圍在 endContainer 中終點的偏移量(與 startOffset 遵循相同的取值規則)。
  • commonAncestorContainer:startContainer 和 endContainer 共同的祖先節點在文檔樹 中位置深的那個。 

在把範圍放到文檔中特定的位置時,這些屬性都會被賦值。 

1. 用 DOM範圍實現簡單選擇 

要使用範圍來選擇文檔中的一部分,簡的方式就是使用 selectNode()或 selectNodeContents()。 這兩個方法都接受一個參數,即一個 DOM 節點,然後使用該節點中的信息來填充範圍。其中,selectNode()方法選擇整個節點,包括其子節點;而 selectNodeContents()方法則只選擇節點的 子節點。以下面的 HTML代碼爲例。 

<!DOCTYPE html>
 <html>     
  <body>           
      <p id="p1">
        <b>Hello</b> world!
     </p>     
</body>
 </html> 

我們可以使用下列代碼來創建範圍

var range1 = document.createRange();     
range2 = document.createRange();    
 p1 = document.getElementById("p1"); 
range1.selectNode(p1);
 range2.selectNodeContents(p1); 
 

這裏創建的兩個範圍包含文檔中不同的部分:rang1 包含<p/>元素及其所有子元素,而 rang2 包 含<b/>元素、文本節點"Hello"和文本節點"world!"(如圖 所示) 。 

在調用 selectNode()時,startContainer、endContainer 和 commonAncestorContainer 都等於傳入節點的父節點,也就是這個例子中的 document.body。而 startOffset 屬性等於給定節 點在其父節點的 childNodes 集合中的索引(在這個例子中是 1——因爲兼容 DOM的瀏覽器將空格算 作一個文本節點),endOffset 等於 startOffset 加 1(因爲只選擇了一個節點)。 

在調用 selectNodeContents()時,startContainer、endContainer 和 commonAncestorConta- iner 等於傳入的節點,即這個例子中的<p>元素。而 startOffset 屬性始終等於 0,因爲範圍從給定節 點的第一個子節點開始。後,endOffset 等於子節點的數量(node.childNodes.length),在這個例 子中是 2。 

 

此外,爲了更精細地控制將哪些節點包含在範圍中,還可以使用下列方法。 

  •  setStartBefore(refNode):將範圍的起點設置在 refNode 之前,因此 refNode 也就是範圍 選區中的第一個子節點。同時會將 startContainer 屬性設置爲 refNode.parentNode,將 startOffset 屬性設置爲 refNode 在其父節點的 childNodes 集合中的索引。 
  • setStartAfter(refNode):將範圍的起點設置在 refNode 之後,因此 refNode 也就不在範 圍之內了,其下一個同輩節點纔是範圍選區中的第一個子節點。同時會將 startContainer 屬 性設置爲 refNode.parentNode,將 startOffset 屬性設置爲 refNode 在其父節點的 childNodes 集合中的索引加 1。 
  • setEndBefore(refNode):將範圍的終點設置在 refNode 之前,因此 refNode 也就不在範圍 之內了,其上一個同輩節點纔是範圍選區中的後一個子節點。同時會將 endContainer 屬性設置爲refNode.parentNode,將endOffset 屬性設置爲refNode在其父節點的childNodes 集合中的索引。 
  • setEndAfter(refNode):將範圍的終點設置在 refNode 之後,因此 refNode 也就是範圍選區 中的後一個子節點。同時會將 endContainer 屬性設置爲 refNode.parentNode,將 endOffset 屬性設置爲 refNode 在其父節點的 childNodes 集合中的索引加 1。 

在調用這些方法時,所有屬性都會自動爲你設置好。不過,要想創建複雜的範圍選區,也可以直接 指定這些屬性的值。 

2. 用 DOM範圍實現複雜選擇 

要創建複雜的範圍就得使用 setStart()和 setEnd()方法。這兩個方法都接受兩個參數:一個參 照節點和一個偏移量值。對 setStart()來說,參照節點會變成 startContainer,而偏移量值會變成 startOffset。對於 setEnd()來說,參照節點會變成 endContainer,而偏移量值會變成 endOffset。

可以使用這兩個方法來模仿 selectNode()和 selectNodeContents()。來看下面的例子: 
 

var range1 = document.createRange();     
range2 = document.createRange();     
p1 = document.getElementById("p1");     
p1Index = -1;     
i, len; 
for (i=0, len=p1.parentNode.childNodes.length; i < len; i++) {     
    if (p1.parentNode.childNodes[i] == p1) {         
        p1Index = i;         
        break;     
    } 
}          
range1.setStart(p1.parentNode, p1Index); 
range1.setEnd(p1.parentNode, p1Index + 1); 
range2.setStart(p1, 0); 
range2.setEnd(p1, p1.childNodes.length); 

顯然,要選擇這個節點(使用 range1),就必須確定當前節點(p1)在其父節點的 childNodes 集合中的索引。而要選擇這個節點的內容(使用 range2),也不必計算什麼;只要通過 setStart() 和 setEnd()設置默認值即可。模仿 selectNode()和 selectNodeContents()並不是 setStart() 和 setEnd()的主要用途,它們更勝一籌的地方在於能夠選擇節點的一部分。 

假設你只想選擇前面 HTML 示例代碼中從"Hello"的"llo"到"world!"的"o"——很容易做到。 第一步是取得所有節點的引用,如下面的例子所示: 

var p1 = document.getElementById("p1");     
helloNode = p1.firstChild.firstChild;    
 worldNode = p1.lastChild;  
 

 

實際上,"Hello"文本節點是<p>元素的孫子節點,因爲它本身是<b>元素的一個子節點。因此, p1.firstChild取得的是<b>,而p1.firstChild.firstChild取得的纔是這個文本節點。"world!" 文本節點是<p>元素的第二個子節點(也是後一個子節點),因此可以使用 p1.lastChild 取得該節點。然後,必須在創建範圍時指定相應的起點和終點,如下面的例子所示。


 var range = document.createRange(); 
range.setStart(helloNode, 2); 
range.setEnd(worldNode, 3); 
 

因爲這個範圍的選區應該從"Hello"中"e"的後面開始,所以在 setStart()中傳入 helloNode 的同時,傳入了偏移量 2(即"e"的下一個位置;"H"的位置是 0)。設置選區的終點時,在 setEnd() 中傳入 worldNode 的同時傳入了偏移量 3,表示選區之外的第一個字符的位置,這個字符是"r",它的 位置是 3(位置 0上還有一個空格)。如圖 12-7所示。 

 

由於helloNode 和worldNode都是文本節點,因此它們分別變成了新建範圍的startContainer 和 endContainer。此時 startOffset 和 endOffset 分別用以確定兩個節點所包含的文本中的位置, 而不是用以確定子節點的位置(就像傳入的參數爲元素節點時那樣)。此時的 commonAncestor- Container 是<p>元素,也就是同時包含這兩個節點的第一個祖先元素。 

當然,僅僅是選擇了文檔中的某一部分用處並不大。但重要的是,選擇之後纔可以對選區進行操作。

3. 操作 DOM範圍中的內容 

在創建範圍時 ,內部會爲這個範圍創建一個文檔片段,範圍所屬的全部節點都被添加到了這個文檔 片段中。爲了創建這個文檔片段,範圍內容的格式必須正確有效。在前面的例子中,我們創建的選區分 別開始和結束於兩個文本節點的內部,因此不能算是格式良好的 DOM結構,也就無法通過 DOM來表 示。

但是,範圍知道自身缺少哪些開標籤和閉標籤,它能夠重新構建有效的 DOM結構以便我們對其進 行操作。 對於前面的例子而言,範圍經過計算知道選區中缺少一個開始的<b>標籤,因此就會在後臺動態加 入一個該標籤,同時還會在前面加入一個表示結束的</b>標籤以結束"He"。於是,修改後的 DOM 就 變成了如下所示。 

<p><b>He</b><b>llo</b> world!</p> 

另外,文本節點"world!"也被拆分爲兩個文本節點,一個包含"wo",另一個包含"rld!"。最終的 DOM樹如圖 12-8所示,右側是表示範圍的文檔片段的內容。

像這樣創建了範圍之後,就可以使用各種方法對範圍的內容進行操作了(注意,表示範圍的內部文 檔片段中的所有節點,都只是指向文檔中相應節點的指針)。

第一個方法,也是容易理解的方法,就是 deleteContents()。這個方法能夠從文檔中刪除範 圍所包含的內容。例如: 
 

var p1 = document.getElementById("p1");    
 helloNode = p1.firstChild.firstChild;     
worldNode = p1.lastChild;         
range = document.createRange(); 

range.setStart(helloNode, 2); 
range.setEnd(worldNode, 3); 
 
range.deleteContents(); 

執行以上代碼後,頁面中會顯示如下 HTML代碼: 

<p><b>He</b>rld!</p>   

由於範圍選區在修改底層 DOM 結構時能夠保證格式良好,因此即使內容被刪除了,終的 DOM 結構依舊是格式良好的。 與 deleteContents()方法相似,extractContents()也會從文檔中移除範圍選區。但這兩個方 法的區別在於,extractContents()會返回範圍的文檔片段。利用這個返回的值,可以將範圍的內容 插入到文檔中的其他地方。如下面的例子所示: 

var p1 = document.getElementById("p1");     
helloNode = p1.firstChild.firstChild;    
 worldNode = p1.lastChild;     
range = document.createRange(); 
 
range.setStart(helloNode, 2);
 range.setEnd(worldNode, 3); 
 
var fragment = range.extractContents(); 
p1.parentNode.appendChild(fragment); 

在這個例子中,我們將提取出來的文檔片段添加到了文檔<body>元素的末尾。(記住,在將文檔片 段傳入 appendChild()方法中時,添加到文檔中的只是片段的子節點,而非片段本身。)結果得到如下 HTML代碼: 

 

<p><b>He</b>rld!</p> <b>llo</b> wo 

還一種做法,即使用 cloneContents()創建範圍對象的一個副本,然後在文檔的其他地方插入該 副本。如下面的例子所示: 


 

var p1 = document.getElementById("p1"),     

    helloNode = p1.firstChild.firstChild,     
    worldNode = p1.lastChild,     
    range = document.createRange(); 
 
range.setStart(helloNode, 2); 
range.setEnd(worldNode, 3); 
 
var fragment = range.cloneContents(); 
p1.parentNode.appendChild(fragment); 

這個方法與 extractContents()非常類似,因爲它們都返回文檔片段。它們的主要區別在於, cloneContents()返回的文檔片段包含的是範圍中節點的副本,而不是實際的節點。執行上面的操作 後,頁面中的 HTML代碼應該如下所示: 

<p><b>Hello</b> world!</p> <b>llo</b> wo 

有一點請讀者注意,那就是在調用上面介紹的方法之前,拆分的節點並不會產生格式良好的文檔片 段。換句話說,原始的 HTML在 DOM被修改之前會始終保持不變。 

 

 

4. 插入 DOM範圍中的內容 

利用範圍,可以刪除或複製內容,還可以像前面介紹的那樣操作範圍中的內容。使用 insertNode() 方法可以向範圍選區的開始處插入一個節點。假設我們想在前面例子中的 HTML 前面插入以下 HTML 代碼: 

<span style="color: red">Inserted text</span> 

那麼,就可以使用下列代碼: 

var p1 = document.getElementById("p1");      
helloNode = p1.firstChild.firstChild;     
worldNode = p1.lastChild;     
range = document.createRange(); 
 
range.setStart(helloNode, 2); 
range.setEnd(worldNode, 3); 
 
var span = document.createElement("span");
 span.style.color = "red"; 
span.appendChild(document.createTextNode("Inserted text"));
 range.insertNode(span); 

運行以上 JavaScript代碼,就會得到如下 HTML代碼: 

<p id="p1"><b>He<span style="color: red">Inserted text</span>llo</b> world</p>  
 

注意,<span>正好被插入到了"Hello"中的"llo"前面,而該位置就是範圍選區的開始位置。還要 注意的是,由於這裏沒有使用上一節介紹的方法,結果原始的 HTML並沒有添加或刪除<b>元素。使用 這種技術可以插入一些幫助提示信息,例如在打開新窗口的鏈接旁邊插入一幅圖像。 除了向範圍內部插入內容之外,還可以環繞範圍插入內容,此時就要使用 surroundContents() 方法。這個方法接受一個參數,即環繞範圍內容的節點。在環繞範圍插入內容時,後臺會執行下列 步驟。 

(1) 提取出範圍中的內容(類似執行 extractContent());

(2) 將給定節點插入到文檔中原來範圍所在的位置上;

(3) 將文檔片段的內容添加到給定節點中。 

可以使用這種技術來突出顯示網頁中的某些詞句,例如下列代碼: 

var p1 = document.getElementById("p1");    
 helloNode = p1.firstChild.firstChild;     
worldNode = p1.lastChild;     
range = document.createRange();
 range.selectNode(helloNode); 
 
var span = document.createElement("span"); 
span.style.backgroundColor = "yellow";
 range.surroundContents(span); 

 

會給範圍選區加上一個黃色的背景。得到的 HTML代碼如下所示:

<p><b><span style="background-color:yellow">Hello</span></b> world!</p> 

爲了插入<span>,範圍必須包含整個 DOM選區(不能僅僅包含選中的 DOM節點)。 

 

5. 摺疊 DOM範圍 

所謂摺疊範圍,就是指範圍中未選擇文檔的任何部分。可以用文本框來描述摺疊範圍的過程。假設 文本框中有一行文本,你用鼠標選擇了其中一個完整的單詞。然後,你單擊鼠標左鍵,選區消失,而光 標則落在了其中兩個字母之間。同樣,在摺疊範圍時,其位置會落在文檔中的兩個部分之間,可能是範 圍選區的開始位置,也可能是結束位置。

圖 12-9展示了摺疊範圍時發生的情形。 使用 collapse()方法來摺疊範圍,這個方法接受一個參數,一個布爾值,表示要摺疊到範圍的哪 一端。參數 true 表示摺疊到範圍的起點,參數 false 表示摺疊到範圍的終點。要確定範圍已經摺疊完 畢,可以檢查 collapsed 屬性,如下所示: 
 

range.collapse(true);       //摺疊到起點
 alert(range.collapsed);      //輸出 true 

檢測某個範圍是否處於摺疊狀態,可以幫我們確定範圍中的兩個節點是否緊密相鄰。例如,對於下 面的 HTML代碼: 

 

<p id="p1">Paragraph 1</p><p id="p2">Paragraph 2</p>

如果我們不知道其實際構成(比如說,這行代碼是動態生成的) ,那麼可以像下面這樣創建一個範圍。

var p1 = document.getElementById("p1"),     
p2 = document.getElementById("p2"),     range = document.createRange(); 
range.setStartAfter(p1); 
range.setStartBefore(p2); 
alert(range.collapsed);     //輸出 true 

在這個例子中,新創建的範圍是摺疊的,因爲 p1 的後面和 p2 的前面什麼也沒有。 

6. 比較 DOM範圍 

在有多個範圍的情況下,可以使用 compareBoundaryPoints()方法來確定這些範圍是否有公共 的邊界(起點或終點)。這個方法接受兩個參數:表示比較方式的常量值和要比較的範圍。表示比較方 式的常量值如下所示。 

 

  • Range.START_TO_START(0):比較第一個範圍和第二個範圍的起點; 
  • Range.START_TO_END(1):比較第一個範圍的起點和第二個範圍的終點; 
  • Range.END_TO_END(2):比較第一個範圍和第二個範圍的終點; 
  • Range.END_TO_START(3):比較第一個範圍的終點和第一個範圍的起點。 

compareBoundaryPoints()方法可能的返回值如下:如果第一個範圍中的點位於第二個範圍中的 點之前,返回-1;如果兩個點相等,返回 0;如果第一個範圍中的點位於第二個範圍中的點之後,返回 1。來看下面的例子

 

var range1 = document.createRange(); 
var range2 = document.createRange(); 
var p1 = document.getElementById("p1"); 
 
range1.selectNodeContents(p1); 
range2.selectNodeContents(p1); 
range2.setEndBefore(p1.lastChild); 
 
alert(range1.compareBoundaryPoints(Range.START_TO_START, range2));     //0 
alert(range1.compareBoundaryPoints(Range.END_TO_END, range2));         //1 

在這個例子中,兩個範圍的起點實際上是相同的,因爲它們的起點都是由 selectNodeContents() 方法設置的默認值來指定的。因此,第一次比較返回 0。但是,range2 的終點由於調用 setEndBefore() 已經改變了,結果是 range1 的終點位於 range2 的終點後面(見圖 12-10),因此第二次比較返回 1。 

 

7. 複製 DOM範圍 

可以使用 cloneRange()方法複製範圍。這個方法會創建調用它的範圍的一個副本。 

var newRange = range.cloneRange(); 

新創建的範圍與原來的範圍包含相同的屬性,而修改它的端點不會影響原來的範圍。 

8. 清理 DOM範圍 

在使用完範圍之後,好是調用 detach()方法,以便從創建範圍的文檔中分離出該範圍。調用 detach()之後,就可以放心地解除對範圍的引用,從而讓垃圾回收機制回收其內存了。來看下面的 例子。

range.detach();      //從文檔中分離
 range = null;         //解除引用 

在使用範圍的後再執行這兩個步驟是我們推薦的方式。一旦分離範圍,就不能再恢復使用了。 

  IE8及更早版本中的範圍 

雖然 IE9支持 DOM範圍,但 IE8及之前版本不支持 DOM範圍。不過,IE8及早期版本支持一種類 似的概念,即文本範圍(text range)。文本範圍是 IE專有的特性,其他瀏覽器都不支持。顧名思義,文 本範圍處理的主要是文本(不一定是 DOM節點)。通過<body>、<button>、<input>和<textarea> 等這幾個元素,可以調用 createTextRange()方法來創建文本範圍。以下是一個例子: 
 

var range = document.body.createTextRange(); 

像這樣通過 document 創建的範圍可以在頁面中的任何地方使用(通過其他元素創建的範圍則只能 在相應的元素中使用)。與 DOM範圍類似,使用 IE文本範圍的方式也有很多種。 

1. 用 IE範圍實現簡單的選擇 

選擇頁面中某一區域的簡單方式,就是使用範圍的 findText()方法。這個方法會找到第一次出 現的給定文本,並將範圍移過來以環繞該文本。如果沒有找到文本,這個方法返回 false;否則返回 true。同樣,仍然以下面的 HTML代碼爲例。 

<p id="p1"><b>Hello</b> world!</p> 

要選擇"Hello",可以使用下列代碼。 
 

var range = document.body.createTextRange(); var found = range.findText("Hello");

在執行完第二行代碼之後,文本"Hello"就被包圍在範圍之內了。爲此,可以檢查範圍的 text 屬 性來確認(這個屬性返回範圍中包含的文本),或者也可以檢查 findText()的返回值——在找到了文 本的情況下返回值爲 true。例如: 

alert(found);           //true 
alert(range.text);      //"Hello" 

還可以爲 findText()傳入另一個參數,即一個表示向哪個方向繼續搜索的數值。負值表示應該從 當前位置向後搜索,而正值表示應該從當前位置向前搜索。因此,要查找文檔中前兩個"Hello"的實例, 應該使用下列代碼。 

var found = range.findText("Hello"); 
var foundAgain = range.findText("Hello", 1); 

IE中與 DOM中的 selectNode()方法接近的方法是 moveToElementText(),這個方法接受一 個 DOM元素,並選擇該元素的所有文本,包括 HTML標籤。下面是一個例子。 

var range = document.body.createTextRange(); 
var p1 = document.getElementById("p1"); 
range.moveToElementText(p1); 

在文本範圍中包含 HTML的情況下,可以使用 htmlText 屬性取得範圍的全部內容,包括 HTML 和文本,如下面的例子所示。 

alert(range.htmlText); 

IE的範圍沒有任何屬性可以隨着範圍選區的變化而動態更新。不過,其 parentElement()方法倒 是與 DOM的 commonAncestorContainer 屬性類似。

var ancestor = range.parentElement(); 

這樣得到的父元素始終都可以反映文本選區的父節點。 

 

2. 使用 IE範圍實現複雜的選擇 

在 IE 中創建複雜範圍的方法,就是以特定的增量向四周移動範圍。爲此,IE 提供了 4 個方法: move()、moveStart()、moveEnd()和 expand()。這些方法都接受兩個參數:移動單位和移動單位 的數量。其中,移動單位是下列一種字符串值。 

  •  "character":逐個字符地移動。 
  • "word":逐個單詞(一系列非空格字符)地移動。 
  • "sentence":逐個句子(一系列以句號、問號或歎號結尾的字符)地移動。 
  • "textedit":移動到當前範圍選區的開始或結束位置。 

通過 moveStart()方法可以移動範圍的起點,通過 moveEnd()方法可以移動範圍的終點,移動的 幅度由單位數量指定,如下面的例子所示。 

range.moveStart("word", 2);       //起點移動 2 個單詞 
range.moveEnd("character", 1);   //終點移動 1 個字符 

使用 expand()方法可以將範圍規範化。換句話說,expand()方法的作用是將任何部分選擇的文 本全部選中。例如,當前選擇的是一個單詞中間的兩個字符,調用 expand("word")可以將整個單詞都 包含在範圍之內。 

而 move()方法則首先會摺疊當前範圍(讓起點和終點相等),然後再將範圍移動指定的單位數量, 如下面的例子所示。 

range.move("character", 5);     //移動 5 個字符 

調用 move()之後,範圍的起點和終點相同,因此必須再使用 moveStart()或 moveEnd()創建新 的選區。 

3. 操作 IE範圍中的內容 

在 IE中操作範圍中的內容可以使用 text 屬性或 pasteHTML()方法。如前所述,通過 text 屬性 可以取得範圍中的內容文本;但是,也可以通過這個屬性設置範圍中的內容文本。來看一個例子。 

var range = document.body.createTextRange(); 
range.findText("Hello"); 
range.text = "Howdy"; 

如果仍以前面的 Hello World代碼爲例,執行以上代碼後的 HTML代碼如下。 

<p id="p1"><b>Howdy</b> world!</p> 

注意,在設置 text 屬性的情況下,HTML標籤保持不變。 要向範圍中插入 HTML代碼,就得使用 pasteHTML()方法,如下面的例子所示。 

 

var range = document.body.createTextRange(); 
range.findText("Hello"); 
range.pasteHTML("<em>Howdy</em>"); 

執行這些代碼後,會得到如下 HTML。 

<p id="p1"><b><em>Howdy</em></b> world!</p> 

 不過,在範圍中包含 HTML代碼時,不應該使用 pasteHTML(),因爲這樣很容易導致不可預料的 結果——很可能是格式不正確的 HTML。 

4. 摺疊 IE範圍 

IE爲範圍提供的 collapse()方法與相應的 DOM方法用法一樣:傳入 true 把範圍摺疊到起點, 傳入 false 把範圍摺疊到終點。例如: 
 

range.collapse(true);     //摺疊到起點 

可惜的是,沒有對應的 collapsed 屬性讓我們知道範圍是否已經摺疊完畢。爲此,必須使用 boundingWidth 屬性,該屬性返回範圍的寬度(以像素爲單位)。如果 boundingWidth 屬性等於 0, 就說明範圍已經摺疊了: 

 

var isCollapsed = (range.boundingWidth == 0); 

 此外,還有 boundingHeight、boundingLeft 和 boundingTop 等屬性,雖然它們都不像 boundingWidth 那麼有用,但也可以提供一些有關範圍位置的信息。 

5. 比較 IE範圍 

IE中的 compareEndPoints()方法與 DOM範圍的 compareBoundaryPoints()方法類似。這個 方法接受兩個參數:比較的類型和要比較的範圍。比較類型的取值範圍是下列幾個字符串值:"StartToStart"、"StartToEnd"、"EndToEnd"和"EndToStart"。這幾種比較類型與比較 DOM範 圍時使用的幾個值是相同的。 

同樣與 DOM類似的是,compareEndPoints()方法也會按照相同的規則返回值,即如果第一個範 圍的邊界位於第二個範圍的邊界前面,返回-1;如果二者邊界相同,返回 0;如果第一個範圍的邊界位 於第二個範圍的邊界後面,返回 1。仍以前面的 Hello World代碼爲例,下列代碼將創建兩個範圍,一個 選擇"Hello world!"(包括<b>標籤),另一個選擇"Hello"。 

var range1 = document.body.createTextRange(); 
var range2 = document.body.createTextRange(); 
 
range1.findText("Hello world!"); range2.findText("Hello"); 
 

alert(range1.compareEndPoints("StartToStart", range2));      //0 
alert(range1.compareEndPoints("EndToEnd", range2));       //1 

由於這兩個範圍共享同一個起點,所以使用 compareEndPoints()比較起點返回 0。而 range1 的終點在 range2 的終點後面,所以 compareEndPoints()返回 1。 IE 中還有兩個方法,也是用於比較範圍的:isEqual()用於確定兩個範圍是否相等,inRange() 用於確定一個範圍是否包含另一個範圍。下面是相應的示例。 
 

var range1 = document.body.createTextRange(); 
var range2 = document.body.createTextRange(); 
range1.findText("Hello World");
 range2.findText("Hello"); 
alert("range1.isEqual(range2): " + range1.isEqual(range2));  //false 
alert("range1.inRange(range2):" + range1.inRange(range2));    //true 

這個例子使用了與前面相同的範圍來示範這兩個方法。由於這兩個範圍的終點不同,所以它們不相 等,調用 isEqual()返回 false。由於 range2 實際位於 range1 內部,它的終點位於後者的終點之 前、起點之後,所以 range2 被包含在 range1 內部,調用 inRange()返回 true。 

6. 複製 IE範圍 

在 IE中使用 duplicate()方法可以複製文本範圍,結果會創建原範圍的一個副本,如下面的例子 所示。 

var newRange = range.duplicate(); 

新創建的範圍會帶有與原範圍完全相同的屬性。 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章