爲了讓開發人員更方便控制頁面,DOM2
級遍歷和範圍模塊定義了 範圍 (range) 接口。經過範圍能夠選擇文檔中的一個區域,而沒必要考慮節點的界限(選擇在後臺完成,對用戶是不可見的)。 Firefox
、Opera
、Safari
和 Chrome
都支持 DOM
範圍。IE 以專有方式實現了本身的範圍特性。javascript
DOM2
級在 Document
類型中定義了 createRange()
方法。在兼容 DOM
的瀏覽器中,使用這個方法屬於 document
對象。使用 hasFeature()
或者直接檢測該方法,均可以肯定瀏覽器是否支持範圍。html
var supportsRange = document.implementation.hasFeature("Range","2.0");
var alsoSupportsRange = (typeof document.createRange == "function");
複製代碼
若是瀏覽器支持範圍,那麼就可使用 createRange()
來建立 DOM
範圍,例如:java
var range = document.createRange();
複製代碼
與節點相似,新建立的範圍與建立它的文檔關聯在一塊兒,不能用於其餘文檔。 每一個範圍由一個Range
類型的實例表示,這個實例擁有不少屬性和方法。下列屬性提供了當前範圍在文檔中的位置信息:node
一、startContainer
:包含範圍起點的節點(即選區中第一個節點的父節點)。git
二、startOffset
:範圍在 startContainer 中起點的偏移量。github
三、endContainer
:包含範圍終點的節點(即選區中最後一個節點的父節點)。瀏覽器
四、endOffset
:範圍在 endContainer 中終點的偏移量。app
五、commonAncestorContainer
:startContainer 和 endContainer 共同的祖先節點。ui
下面簡單介紹一下範圍的使用方法:spa
要使用範圍來選擇文檔中的一部分,最簡單的方式是使用 selectNode()
或 selectNodeContents()
,例如:
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<p id="p1"><b>Hello</b> world!</p>
<script> var range1 = document.createRange(), range2 = document.createRange(), p1 = document.getElementById("p1"); range1.selectNode(p1); range2.selectNodeContents(p1); </script>
</body>
</html>
複製代碼
兩個範圍包含文檔中不一樣部分,如圖:
在調用selectNode()
時,
startContainer
、
endContainer
都等於傳入節點的父節點,也就是
document.body
。而
startOffset
屬性等於給定節點在其父節點的
childNodes
集合中的索引(在這個例子中是
1
,由於兼容
DOM
的瀏覽器將空格算做一個文本節點),
endOffset
等於
startOffset
加
1
(由於只選擇了一個節點)。 在調用
selectNodeContents()
時,
startContainer
、
endContainer
等於傳入的節點,即這個例子中的
<p>
元素。而
startOffset
屬性始終等於
0
,由於範圍從給定節點的第一個子節點開始。最後,
endOffset
等於子節點的數量(node.childNodes.length),在這個例子中是
2
。例如:
console.log(range1.startContainer); //<body>...</body>
console.log(range2.startContainer); //<p id="p1">...</p>
console.log(range1.endContainer); //<body>...</body>
console.log(range2.endContainer); //<p id="p1">...</p>
console.log(range1.startOffset); //1
console.log(range2.startOffset); //0
console.log(range1.endOffset); //2
console.log(range2.endOffset); //2
複製代碼
此外,爲了更精細地控制哪些節點包含在範圍內,還可使用下列方法:
一、setStartBefore(refNode)
:將範圍的起點設置在 refNode 以前。
二、setStartAfter(refNode)
:將範圍的起點設置在refNode 以後。
三、setEndBefore(refNode)
:將範圍的終點設置在 refNode 以前。
四、setEndAfter(refNode)
:將範圍的終點設置在 refNode 以後。
要建立複雜的範圍就得使用 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);
複製代碼
假設你只想選擇前面 HTML
示例代碼中從 hello
的 llo
到 world!
的 o
,能夠這樣作:
var p1 = document.getElementById("p1"),
helloNode = p1.firstChild.firstChild,
worldNode = p1.lastChild;
var range = document.createRange();
range.setStart(helloNode,2);
range.setEnd(worldNode,3);
複製代碼
因爲 helloNode
和 worldNode
都是文本節點,所以它們分別變成了新建範圍的 startContainer
和 endContainer
。此時 startOffset
和 endOffset
分別用以肯定兩個節點所包含的文本中的位置,而不是用以肯定子節點的位置。如圖:
對前面的例子而言,範圍通過計算知道選取中缺乏一個開始的 <b>
標籤,所以就會在後臺動態添加一個該標籤,同時還會在前面加入一個表示結束的 <b>
標籤。因而修改後的 DOM
就變成以下所示: <p><b>He</b><b>llo</b> world!</p>
。
像這樣建立了範圍以後,就可使用各類方法對範圍的內容進行操做了。 第一個方法:deleteContents()
,從文檔中刪除範圍所包含的內容。例如:
range.deleteContents();
複製代碼
執行這句代碼以後,頁面會顯示以下 HTML
代碼:
<p id="p1"><b>He</b>rld!</p>
複製代碼
第二個方法:extractContents()
,也會從文檔中移除範圍選區,但會返回文檔片斷。例如:
var fragment = range.extractContents();
p1.parentNode.appendChild(fragment);
複製代碼
執行這句代碼以後,頁面會顯示以下 HTML
代碼:
<p id="p1"><b>He</b>rld!</p><b>llo</b> wo
複製代碼
第三個方法:cloneContents()
,會建立範圍對象的一個副本,而後插入到其餘地方。例如:
var fragment = range.cloneContents();
p1.parentNode.appendChild(fragment);
複製代碼
執行這句代碼以後,頁面會顯示以下 HTML
代碼:
<p id="p1"><b>Hello</b> world!</p><b>llo</b> wo
複製代碼
利用範圍,能夠刪除或複製內容,也可使用 insertNode()
方法像範圍選區的開始處插入一個節點。假設咱們在前面例子中的 HTML
前面插入如下 HTML
代碼:<span style="color:red;">Inserted text</span>
,那麼可使用如下代碼:
var span = document.createElement("span");
span.style.color = "red";
span.appendChild(document.createTextNode("Inserted text"));
range.insertNode(span);
複製代碼
執行這句代碼以後,頁面會顯示以下 HTML
代碼:
<p id="p1"><b>He<span style="color: red;">Inserted text</span>llo</b> world!</p>
複製代碼
注意:<span>
正好被插入到了 hello
中的 llo
前面,而該位置就是範圍選區的開始位置。還要注意的是,這裏並無添加或刪除 <b>
元素,使用這種技術能夠插入一些幫助提示信息,例如在打開新窗口的連接旁插入一幅圖像。
除了像範圍內部插入內容以外,還能夠圍繞範圍插入內容,此時就要使用 surroundContents()
方法。該方法接受一個參數,即環繞範圍內容的節點。例如:
range.selectNode(helloNode);
var span = document.createElement("span");
span.style.backgroundColor = "yellow";
range.surroundContents(span);
複製代碼
執行這句代碼以後,會給範圍選區加上一個黃色背景。獲得的 HTML
代碼以下所示:
<p id="p1"><b><span style="background-color: yellow;">Hello</span></b> world!</p>
複製代碼
注意:爲了插入 <span>
,範圍必須包含整個 DOM
選區(不能僅僅包含選中的 DOM
節點)。
所謂 摺疊範圍 ,就是指範圍中未選擇文檔的任何部分。使用 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.setEndBefore(p2);
alert(range.collapsed); //true
複製代碼
在這個例子中,建立的範圍是摺疊的,因此 p1
和 p1
是相鄰的。
在有多個範圍的狀況下,可使用 compareBoundaryPoints()
方法來肯定這些範圍是否有公共的邊界。這個方法接受兩個參數:表示比較方式的常量值和要比較的範圍。表示比較方式的常量以下:
一、Range.START_TO_START
:比較第一個範圍和第二個範圍的起點;
二、Range.START_TO_END
:比較第一個範圍的起點和第二個範圍的終點;
三、Range.END_TO_END
:比較第一個範圍和第二個範圍的終點;
四、Range.END_TO_START
:比較第一個範圍的終點和第二個範圍的起點;
compareBoundaryPoints()
方法返回值以下:若是第一個範圍中的點位於第二個範圍中的點以前,返回 -1
;若是兩個點相等,返回 0
;若是第一個範圍中的點位於第二個範圍中的點以後,返回 1
。例如:
var range1 = document.createRange(),
range2 = document.createRange(),
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
複製代碼
這個例子中,兩個範圍的起點相同,第一個範圍的終點位於第二個範圍的終點後面,如圖:
可使用 cloneRange()
方法複製範圍,這個方法會建立調用它的範圍的一個副本。
var newRange = range.cloneRange();
複製代碼
新建立的範圍與原來的範圍包含相同的屬性,而修改它的端點不會影響原來的範圍。
在使用完範圍後,最好是調用 detach()
方法,以便從建立範圍的文檔中分離出該範圍。調用 detach()
以後,就能夠放心地解除對範圍的引用,從而讓垃圾回收機制回收其內存了。例如:
range.detach(); //從文檔中分離
range = null; //解除引用
複製代碼
在使用範圍的最後在執行這兩個步驟是咱們推薦的方式,一旦分離範圍,就不能在恢復使用了。
IE9
支持範圍,但 IE8
及以前版本不支持範圍。不過,IE8
及早起版本支持一種相似的概念,即 文本範圍(text range) 。文本範圍是 IE
專有特性,主要處理文本(不必定是 DOM
節點)。經過 <body>
、 <button>
、<input>
和<textarea>
等幾個元素,能夠調用 createTextRange()
方法來建立文本範圍。例如:
var range = document.body.createTextRange();
複製代碼
與 DOM
範圍相似,使用 IE
文本範圍的方式也有不少種。
選擇頁面中某一區域最簡單的方式,就是使用範圍的 findText()
方法。這個方法會找到第一次出現的給定文本,並將範圍移過來以環繞該文本。若是沒找到文本,這個方法返回 false
;不然,返回 true
。一樣,仍然如下面的 HTML
代碼爲例:
<p id="p1"><b>Hello</b> world!</p>
複製代碼
要選擇 Hello
,可使用如下代碼:
var range = document.body.createTextRange();
var found = range.findText("Hello");
alert(found); //true
alert(range.text); //"Hello"
複製代碼
IE
中與 DOM
中的 selectNode()
方法最接近的方法是 moveToElementText()
,這個方法接受一個 DOM
元素,並選擇該元素的全部文本,包含 HTML
標籤,例如:
var range = document.body.createTextRange(),
p1 = document.getElementById("p1");
range.moveToElementText(p1);
複製代碼
在文本範圍中包含 HTML
的狀況下,可使用 htmlText
屬性取得範圍的所有內容,例如:
alert(range.htmlText);
複製代碼
IE
的範圍沒有任何屬性能夠隨着範圍選區的變化而動態更新。不過,其 parentElement()
方法卻是與DOM
的 commonAncestorContainer
屬性相似。例如:
var ancestor = range.parentElement();
複製代碼
這樣就獲得了範圍選區的父節點。
在 IE
中建立複雜範圍的方法,就是以增量向四周移動範圍。爲此,IE
提供了 4 個方法: move()
、moveStart()
、moveEnd()
和 expand()
。 這些方法都接受兩個參數:移動單位和移動單位的數量。其中,移動單位是下列一種字符串值:
一、character
:這個字符地移動;
二、word
:逐個單詞(一系列非空格字符)地移動;
三、sentence
:逐個句子(一系列以句號、問號或歎號結尾的字符)地移動;
四、textedit
:移動到當前範圍選區的開始或結束位置。
經過 moveStart()
方法能夠移動到範圍的起點,經過 moveEnd()
方法能夠移動到範圍的終點,移動的幅度由單位數量指定,例如:
range.moveStart("word",2); //起點移動 2 個單詞
range.moveEnd("character",1); //終點移動 1 個字符
複製代碼
使用 expand()
方法能夠將範圍規範化。換句話說,能夠將任何部分選擇的文本所有選中。例如:
range.expand("word"); //能夠將整個單詞選中
複製代碼
而 move()
方法則先會摺疊當前範圍,而後再將範圍移動到指定的單位數量,例如:
range.move("character",5); //移動 5 個字符
複製代碼
在 IE
中操做範圍中的內容可使用 text
屬性或 pasteHTML()
方法。如前所述,經過 text
屬性能夠取得範圍中的內容文本;可是,也能夠經過這個屬性設置範圍中的內容文本。例如:
var range = document.body.createTextRange();
range.findText("Hello");
range.text = "Hi";
複製代碼
執行以上代碼後的 HTML
代碼以下:
<p id=p1><b>Hi</b> world!</p>
複製代碼
這時,HTML
標籤保持不變,若要像範圍中插入 HTML
代碼,就得使用 pasteHTMl()
方法,例如:
var range = document.body.createTextRange();
range.findText("Hello");
range.pasteHTML("<em>Hi</em>");
複製代碼
執行以上代碼後的 HTML
代碼以下:
<p id=p1><b><em>Hi</em></b> world!</p>
複製代碼
注意:在範圍中包含 HTML
代碼時,不該該使用 pasteHTML()
,由於這樣很容易致使不可預料的結果(極可能是格式不正確的 HTML
)。
IE
爲範圍提供的 collapse()
方法與 DOM
方法用法同樣,惋惜,沒有對應的 collapsed
屬性讓咱們知道範圍是否已經摺疊完畢。爲此,必須使用 boundingWidth
屬性,該屬性返回範圍的寬度(以像素爲單位)。若是等於 0
說明範圍已經摺疊。例如:
range.collapse(true);
alert(range.boundingWidth); //0
複製代碼
此外,還有 boundingHeight
、boundingLeft
和boundingTop
等屬性,能夠提供一些位置信息。
IE
中的 compareEndPoints()
方法與 DOM
範圍的 compareBoundaryPoints()
方法相似。這個方法接受兩個參數:比較的類型和要比較的範圍。比較類型的取值範圍是下列幾個字符串值:StartToStart
、 StartToEnd
、EndToEnd
、EndToStart
。 compareEndPoints()
方法返回值同 compareBoundaryPoints()
方法。例如:
var range1 = document.body.createTextRange(),
range2 = document.body.createTextRange();
range1.findText("Hello world!");
range2.findText("Hello");
alert(range1.compareEndPoints("StartToStart",range2)); //0
alert(range1.compareEndPoints("EndToEnd",range2)); //1
複製代碼
IE
中還有兩個方法,也用於比較範圍:isEqual()
方法用於肯定兩個範圍是否相等,inRange()
方法用於肯定一個範圍是否包含另外一個範圍。例如:
var range1 = document.body.createTextRange(),
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
複製代碼
在 IE
中使用 duplicate()
方法能夠複製文本範圍,結果會建立原範圍的一個副本,例如:
var newRange = range.duplicate();
複製代碼
新建立的範圍會帶有與原範圍徹底相同的屬性。
😋😋😋 好了,基本知識就是這些,在這裏和你們說拜拜啦~