這篇文章主要介紹Javascript中DOM范圍的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
十多年的海興網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。成都全網(wǎng)營(yíng)銷推廣的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整海興建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。成都創(chuàng)新互聯(lián)從事“海興網(wǎng)站設(shè)計(jì)”,“海興網(wǎng)站推廣”以來,每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。
創(chuàng)建范圍
Document類型中定義了createRange()
方法。在兼容DOM的瀏覽器中,這個(gè)方法屬于document對(duì)象。使用hasFeature()
或者直接檢測(cè)該方法,都可以確定瀏覽器是否支持范圍
[注意]IE8-瀏覽器不支持
var supportsRange = document.implementation.hasFeature("Range", "2.0"); var alsoSupportsRange =(typeof document.createRange == "function");
如果瀏覽器支持范圍,那么就可以使用createRange()
來創(chuàng)建DOM范圍,如下所示
var range = document.createRange();
與節(jié)點(diǎn)類似,新創(chuàng)建的范圍也直接與創(chuàng)建它的文檔關(guān)聯(lián)在一起,不能用于其他文檔。創(chuàng)建了范圍之后,接下來就可以使用它在后臺(tái)選擇文檔中的特定部分。而創(chuàng)建范圍并設(shè)置了其位置之后,還可以針對(duì)范圍的內(nèi)容執(zhí)行很多種操作,從而實(shí)現(xiàn)對(duì)底層DOM樹的更精細(xì)的控制
每個(gè)范圍由一個(gè)Range類型的實(shí)例表示,這個(gè)實(shí)例擁有很多屬性和方法。
下列屬性提供了當(dāng)前范圍在文檔中的位置信息
startContainer:包含范圍起點(diǎn)的節(jié)點(diǎn)(即選區(qū)中第一個(gè)節(jié)點(diǎn)的父節(jié)點(diǎn))
startoffset:范圍在startContainer中起點(diǎn)的偏移量。如果startContainer是文本節(jié)點(diǎn)、注釋節(jié)點(diǎn)或CDATA節(jié)點(diǎn),那么startoffset就是范圍起點(diǎn)之前跳過的字符數(shù)量。否則,startoffset就是范圍中第一個(gè)子節(jié)點(diǎn)的索引
endContainer:包含范圍終點(diǎn)的節(jié)點(diǎn)(即選區(qū)中最后一個(gè)節(jié)點(diǎn)的父節(jié)點(diǎn))
endOffset:范圍在endContainer中終點(diǎn)的偏移量(與startoffset遵循相同的取值規(guī)則)
commonAncestorContainer:startContainer和endContainer共同的祖先節(jié)點(diǎn)在文檔樹中位置最深的那個(gè)
在把范圍放到文檔中特定的位置時(shí),這些屬性都會(huì)被賦值
簡(jiǎn)單選擇
要使用范圍來選擇文檔中的一部分,最簡(jiǎn)單的方式就是使用selectNode()
或selectNodeContents()
。這兩個(gè)方法都接受一個(gè)參數(shù),即一個(gè)DOM節(jié)點(diǎn),然后使用該節(jié)點(diǎn)中的信息來填充范圍。其中,selectNode()
方法選擇整個(gè)節(jié)點(diǎn),包括其子節(jié)點(diǎn);而selectNodeContents()
方法則只選擇節(jié)點(diǎn)的子節(jié)點(diǎn)
<!DOCTYPE html> <html> <body> <p id="p1"><b>Hello</b> world!</p> </body> </html>
我們可以使用下列代碼來創(chuàng)建范圍
var range1 = document.createRange(); var range2 = document.createRange(); var p1 = document.getElementById("p1"); //Range {startContainer: body, startOffset: 1, endContainer: body, endOffset: 2, collapsed: false…} range1.selectNode(p1); //Range {startContainer: p#p1, startOffset: 0, endContainer: p#p1, endOffset: 2, collapsed: false…} range2.selectNodeContents(p1);
這里創(chuàng)建的兩個(gè)范圍包含文檔中不同的部分:rangl包含<p>元素及其所有子元素,而rang2包含<b>元素、文本節(jié)點(diǎn)"Hello"和文本節(jié)點(diǎn)"world!"
在調(diào)用selectNode()
時(shí),startContainer、endContainer和commonAncestorContainer都等于傳入節(jié)點(diǎn)的父節(jié)點(diǎn),也就是這個(gè)例子中的document.body
。而startoffset屬性等于給定節(jié)點(diǎn)在其父節(jié)點(diǎn)的childNodes集合中的索引(在這個(gè)例子中是1——因?yàn)榧嫒軩OM的瀏覽器將空格算作一個(gè)文本節(jié)點(diǎn)),endOffset等于startoffset加1(因?yàn)橹贿x擇了一個(gè)節(jié)點(diǎn))
在調(diào)用selectNodeContents()
時(shí),startContainer、endContainer和commonAncestorContainer等于傳入的節(jié)點(diǎn),即這個(gè)例子中的<p>元素。而startoffset屬性始終等于0,因?yàn)榉秶鷱慕o定節(jié)點(diǎn)的第一個(gè)子節(jié)點(diǎn)開始。最后,endOffset等于子節(jié)點(diǎn)的數(shù)量(node.childNodes.length
),在這個(gè)例子中是2
此外,為了更精細(xì)地控制將哪些節(jié)點(diǎn)包含在范圍中,還可以使用下列方法
setStartBefore(refNode)
:將范圍的起點(diǎn)設(shè)置在refNode之前,因此refNode也就是范圍選區(qū)中的第一個(gè)子節(jié)點(diǎn)。同時(shí)會(huì)將startContainer屬性設(shè)置為refNode.parentNode,將startoffset屬性設(shè)置為refNode在其父節(jié)點(diǎn)的childNodes集合中的索引
setStartAfter(refNode)
:將范圍的起點(diǎn)設(shè)置在refNode之后,因此refNode也就不在范圍之內(nèi)了,其下一個(gè)同輩節(jié)點(diǎn)才是范圍選區(qū)中的第一個(gè)子節(jié)點(diǎn)。同時(shí)會(huì)將startContainer屬性設(shè)置為refNode.parentNode,將startoffset屬性設(shè)置為refNode在其父節(jié)點(diǎn)的childNodes集合中的索引加1
setEndBefore(refNode)
:將范圍的終點(diǎn)設(shè)置在refNode之前,因此refNode也就不在范圍之內(nèi)了,其上一個(gè)同輩節(jié)點(diǎn)才是范圍選區(qū)中的最后一個(gè)子節(jié)點(diǎn)。同時(shí)會(huì)將endContainer屬性設(shè)置為refNode.parentNode,將endOffset屬性設(shè)置為refNode在其父節(jié)點(diǎn)的childNodes集合中的索引
setEndAfter(refNode)
:將范圍的終點(diǎn)設(shè)置在refNode之后,因此refNode也就是范圍選區(qū)中的最后一個(gè)子節(jié)點(diǎn)。同時(shí)會(huì)將endContainer屬性設(shè)置為refNode.parentNode,將endOffset屬性設(shè)置為refNode在其父節(jié)點(diǎn)的childNodes集合中的索引加1
調(diào)用這些方法時(shí),所有屬性會(huì)自動(dòng)設(shè)置好。不過,要想創(chuàng)建復(fù)雜的范圍選區(qū),也可以直接指定這些屬性的值
復(fù)雜選擇
要?jiǎng)?chuàng)建復(fù)雜的范圍就得使用setStart()
和setEnd()
方法。這兩個(gè)方法都接受兩個(gè)參數(shù):一個(gè)參照節(jié)點(diǎn)和一個(gè)偏移量值。對(duì)setStart()
來說,參照節(jié)點(diǎn)會(huì)變成startContainer。而偏移量值會(huì)變成startoffset。對(duì)于setEnd()
來說,參照節(jié)點(diǎn)會(huì)變成endContainer,而偏移量值會(huì)變成endOffset??梢允褂眠@兩個(gè)方法來模仿selectNode()
和selectNodeContents()
。
來看下面的例子
var range1 = document.createRange(); var range2 = document.createRange(); var p1 = document.getElementById("p1"); var p1Index = -1; var 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);
顯然,要選擇這個(gè)節(jié)點(diǎn)(使用range1),就必須確定當(dāng)前節(jié)點(diǎn)(p1)在其父節(jié)點(diǎn)的childNodes集合中的索引。而要選擇這個(gè)節(jié)點(diǎn)的內(nèi)容(使用range2),也不必計(jì)算什么;只要通過setStart()和setEnd()設(shè)置默認(rèn)值即可。模仿selectNode()
和selectNodeContents()
并不是setStart()
和setEnd()
的主要用途,它們更勝一籌的地方在于能夠選擇節(jié)點(diǎn)的一部分
假設(shè)只想選擇前面HTML示例代碼中從“Hello"的"llo"到"world!"的"o"——很容易做到
第一步是取得所有節(jié)點(diǎn)的引用,如下所示:
var p1 = document.getElementById("p1"); var helloNode = p1.firstChild.firstChild; var worldNode = p1.lastChild;
實(shí)際上,"Hello”文本節(jié)點(diǎn)是<p>元素的孫子節(jié)點(diǎn),因?yàn)樗旧硎?lt;b>元素的一個(gè)子節(jié)點(diǎn)。因此,p1.firstchild
取得的是<b>,而p1.firstchild.firstchild
取得的才是這個(gè)文本節(jié)點(diǎn)。"world!"文本節(jié)點(diǎn)是<p>元素的第二個(gè)子節(jié)點(diǎn)(也是最后一個(gè)子節(jié)點(diǎn)),因此可以使用p1.lastChild
取得該節(jié)點(diǎn)。
然后,必須在創(chuàng)建范圍時(shí)指定相應(yīng)的起點(diǎn)和終點(diǎn),如下所示
var range = document.createRange(); range.setStart(helloNode, 2); range.setEnd(worldNode, 3);
因?yàn)檫@個(gè)范圍的選區(qū)應(yīng)該從"Hello"中"e"的后面開始,所以在setStart()
中傳入helloNode的同時(shí),傳入了偏移量2(即"e"的下一個(gè)位置;"H"的位置是0)。設(shè)置選區(qū)的終點(diǎn)時(shí),在setEnd()
中傳入worldNode的同時(shí)傳入了偏移量3,表示選區(qū)之外的第一個(gè)字符的位置,這個(gè)字符是”r",它的位置是3(位置0上還有一個(gè)空格)。
如下所示
由于helloNode和worldNode都是文本節(jié)點(diǎn),因此它們分別變成了新建范圍的startContainer和endContainer。此時(shí)startoffset和endOffset分別用以確定兩個(gè)節(jié)點(diǎn)所包含的文本中的位置,而不是用以確定子節(jié)點(diǎn)的位置(就像傳入的參數(shù)為元素節(jié)點(diǎn)時(shí)那樣)。此時(shí)的commonAncestorContainer是<p>元素,也就是同時(shí)包含這兩個(gè)節(jié)點(diǎn)的第一個(gè)祖先元素
當(dāng)然,僅僅是選擇了文檔中的某一部分用處并不大。但重要的是,選擇之后才可以對(duì)選區(qū)進(jìn)行操作
操作范圍內(nèi)容
在創(chuàng)建范圍時(shí),內(nèi)部會(huì)為這個(gè)范圍創(chuàng)建一個(gè)文檔片段,范圍所屬的全部節(jié)點(diǎn)都被添加到了這個(gè)文檔片段中。為了創(chuàng)建這個(gè)文檔片段,范圍內(nèi)容的格式必須正確有效。在前面的例子中,創(chuàng)建的選區(qū)分別開始和結(jié)束于兩個(gè)文本節(jié)點(diǎn)的內(nèi)部,因此不能算是格式良好的DOM結(jié)構(gòu),也就無法通過DOM來表示。但是,范圍知道自身缺少哪些開標(biāo)簽和閉標(biāo)簽,它能夠重新構(gòu)建有效的DOM結(jié)構(gòu)以便對(duì)其進(jìn)行操作
對(duì)于前面的例子而言,范圍經(jīng)過計(jì)算知道選區(qū)中缺少一個(gè)開始的<b>標(biāo)簽,因此就會(huì)在后臺(tái)動(dòng)態(tài)加入一個(gè)該標(biāo)簽,同時(shí)還會(huì)在前面加入一個(gè)表示結(jié)束的</b>標(biāo)簽以結(jié)束"He"。于是,修改后的DOM就變成了如下所示
<p><b>He</b><b>llo</b> world!</p>
另外,文本節(jié)點(diǎn)"world!"也被拆分為兩個(gè)文本節(jié)點(diǎn),一個(gè)包含"wo",另一個(gè)包含"rid!"。最終的DOM樹下圖所示,右側(cè)是表示范圍的文檔片段的內(nèi)容
像這樣創(chuàng)建了范圍之后,就可以使用各種方法對(duì)范圍的內(nèi)容進(jìn)行操作了
[注意]表示范圍的內(nèi)部文檔片段中的所有節(jié)點(diǎn),都只是指向文檔中相應(yīng)節(jié)點(diǎn)的指針
【deleteContents()】
操作范圍內(nèi)容的第一個(gè)方法是deleteContents()
,這個(gè)方法能夠從文檔中刪除范圍所包含的內(nèi)容
var p1 = document.getElementById("p1"); var helloNode = p1.firstChild.firstChild; var worldNode = p1.lastChild; var range = document.createRange(); range.setStart(helloNode, 2); range.setEnd(worldNode, 3); range.deleteContents();
執(zhí)行以上代碼后,頁(yè)面中會(huì)顯示如下HTML代碼
<p><b>He</b>rld!</p>
由于范圍選區(qū)在修改底層DOM結(jié)構(gòu)時(shí)能夠保證格式良好,因此即使內(nèi)容被刪除了,最終的DOM結(jié)構(gòu)依舊是格式良好的
【extractContents()】
與deleteContents()
方法相似,extractContents()
方法也會(huì)從文檔中移除范圍選區(qū)。但區(qū)別在于,extractContents()
會(huì)返回范圍的文檔片段。利用這個(gè)返回的值,可以將范圍的內(nèi)容插入到文檔中的其他地方。如下所示:
var p1 = document.getElementById("p1"); var helloNode = p1.firstChild.firstChild; var worldNode = p1.lastChild; var range = document.createRange(); range.setStart(helloNode, 2); range.setEnd(worldNode, 3); var fragment = range.extractContents(); p1.parentNode.appendChild(fragment);
在這個(gè)例子中,將提取出來的文檔片段添加到了文檔<body>元素的末尾
[注意]在將文檔片段傳入appendChild()方法中時(shí),添加到文檔中的只是片段的子節(jié)點(diǎn),而非片段本身
<p><b>He</b>rld!</p> <b>llo</b> wo
【cloneContents】
還有一種做法是使用cloneContents()
創(chuàng)建范圍對(duì)象的一個(gè)副本,然后在文檔其他地方插入該副本
var p1 = document.getElementById("p1"); var helloNode = p1.firstChild.firstChild; var worldNode = p1.lastChild; var range = document.createRange(); range.setStart(helloNode, 2); range.setEnd(worldNode, 3); var fragment = range.cloneContents(); p1.parentNode.appendChild(fragment);
這個(gè)方法與extractContents()
非常類似,因?yàn)樗鼈兌挤祷匚臋n片段。它們的主要區(qū)別在于,cloneContents()
返回的文檔片段包含的是范圍中節(jié)點(diǎn)的副本,而不是實(shí)際的節(jié)點(diǎn)。執(zhí)行上面的操作后,頁(yè)面中的HTML代碼如下所示:
<p><b>Hello</b> world!</p> <b>llo</b> wo
[注意]在調(diào)用cloneContents()方法之前,拆分的節(jié)點(diǎn)并不會(huì)產(chǎn)生格式良好的文檔片段。換句話說,原始的HTML在DOM被修改之前會(huì)始終保持不變
插入范圍內(nèi)容
利用范圍,可以刪除或復(fù)制內(nèi)容,還可以像前面介紹的那樣操作范圍中的內(nèi)容。使用insertNode()
方法可以向范圍選區(qū)的開始處插入一個(gè)節(jié)點(diǎn)。假設(shè)在前面例子中的HTML前面插入以下HTML代碼
<span >Inserted text</span>
那么可以使用下列代碼:
var p1 = document.getElementById("p1"); var helloNode = p1.firstChild.firstChild; var worldNode = p1.lastChild; var range = document.createRange(); var span = document.createElement("span"); range.setStart(helloNode, 2); range.setEnd(worldNode, 3); span.style.color = "red"; span.appendChild(document.createTextNode("Inserted text")); range.insertNode(span);
運(yùn)行以上javascript代碼,就會(huì)得到如下HTML代碼
<p id="p1"><b>He<span styie="color:red">Inserted text</span>llo</b> world</p>
[注意]<span>正好被插入到了"Hello"中的"llo"前面,而該位置就是范圍選區(qū)的開始位置。使用這種技術(shù)可以插入一些幫助提示信息,例如在打開新窗口的鏈接旁邊插入一幅圖像
【surroundContents()】
除了向范圍內(nèi)部插入內(nèi)容之外,還可以環(huán)繞范圍插入內(nèi)容,此時(shí)就要使用surroundContents()
方法。這個(gè)方法接受一個(gè)參數(shù),即環(huán)繞范圍內(nèi)容的節(jié)點(diǎn)。在環(huán)繞范圍插入內(nèi)容時(shí),后臺(tái)會(huì)執(zhí)行下列步驟
1、提取出范圍中的內(nèi)容(類似執(zhí)行extractContents()
)
2、將給定節(jié)點(diǎn)插入到文檔中原來范圍所在的位置上
3、將文檔片段的內(nèi)容添加到給定節(jié)點(diǎn)中
可以使用這種技術(shù)來突出顯示網(wǎng)頁(yè)中的某些詞句,例如下列代碼
var p1 = document.getElementById("p1"); var helloNode = p1.firstChild.firstChild; var worldNode = p1.lastChild; var range = document.createRange(); range.selectNode(helloNode); var span = document.createElement("span"); span.style.backgroundColor = "yellow"; range.surroundContents(span);
以上代碼會(huì)給范圍選區(qū)加上一個(gè)黃色的背景。得到的HTML代碼如下所示
<p><b><span >Hello</b> world!</p>
為了插入<span>,范圍必須包含整個(gè)DOM選區(qū),而不能僅僅包含選中的DOM節(jié)點(diǎn)
折疊范圍
所謂折疊范圍,就是指范圍中未選擇文檔的任何部分??梢杂梦谋究騺砻枋稣郫B范圍的過程。假設(shè)文本框中有一行文本,用鼠標(biāo)選擇了其中一個(gè)完整的單詞。然后,單擊鼠標(biāo)左鍵,選區(qū)消失,而光標(biāo)則落在了其中兩個(gè)字母之間。同樣,在折疊范圍時(shí),其位置會(huì)落在文檔中的兩個(gè)部分之間,可能是范圍選區(qū)的開始位置,也可能是結(jié)束位置。下圖展示了折疊范圍時(shí)發(fā)生的情形
【collapse()】
使用collapse()
方法來折疊范圍,這個(gè)方法接受一個(gè)參數(shù),該參數(shù)是一個(gè)布爾值,表示要折疊到范圍的哪一端。參數(shù)true表示折疊到范圍的起點(diǎn),參數(shù)false表示折疊到范圍的終點(diǎn)。要確定范圍已經(jīng)折疊完畢,可以檢査collapsed屬性,如下所示:
range.collapse(true);//折疊到起點(diǎn) console.log(range.collapsed);//輸出true
檢測(cè)某個(gè)范圍是否處于折疊狀態(tài),可以幫我們確定范圍中的兩個(gè)節(jié)點(diǎn)是否緊密相鄰。例如,對(duì)于下面的HTML代碼
<p id="p1">Paragraph 1</p><p id="p2">Paragraph 2</p>
如果不知道其實(shí)際構(gòu)成(比如說,這行代碼是動(dòng)態(tài)生成的),那么可以像下面這樣創(chuàng)建一個(gè)范圍
var p1 = document.getElementById("p1"); var p2 = document.getElementById("p2"); var range = document.createRange(); range.setStartAfter(p1); range.setStartBefore(p2); console.log(range.collapsed);//輸出true
在這個(gè)例子中,新創(chuàng)建的范圍是折疊的,因?yàn)閜1的后面和p2的前面什么也沒有
比較范圍
【compareBoundaryPoints()】
在有多個(gè)范圍的情況下,可以使用compareBoundaryPoints()
方法來確定這些范圍是否有公共的邊界(起點(diǎn)或終點(diǎn))。這個(gè)方法接受兩個(gè)參數(shù):表示比較方式的常量值和要比較的范圍。表示比較方式的常量值如下所示
Range.START_TO_START(0)
:比較第一個(gè)范圍和第二個(gè)范圍的起點(diǎn)
Range.START_TO_END(1)
:比較第一個(gè)范圍的起點(diǎn)和第二個(gè)范圍的終點(diǎn)
Range.END_TO_END⑵
:比較第一個(gè)范圍和第二個(gè)范圍的終點(diǎn)
Range.END_T0_START(3)
:比較第一個(gè)范圍的終點(diǎn)和第一個(gè)范圍的起點(diǎn)
compareBoundaryPoints()
方法可能的返回值如下:如果第一個(gè)范圍中的點(diǎn)位于第二個(gè)范圍中的點(diǎn)之前,返回-1;如果兩個(gè)點(diǎn)相等,返回0;如果第一個(gè)范圍中的點(diǎn)位于第二個(gè)范圍中的點(diǎn)之后,返回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)); //outputs 0 alert(range1.compareBoundaryPoints(Range.END_TO_END, range2)); //outputs 1
在這個(gè)例子中,兩個(gè)范圍的起點(diǎn)實(shí)際上是相同的,因?yàn)樗鼈兊钠瘘c(diǎn)都是由selectNodeContents()
方法設(shè)置的默認(rèn)值來指定的。因此,第一次比較返回0。但是,range2的終點(diǎn)由于調(diào)用setEndBefore()
已經(jīng)改變了,結(jié)果是range1的終點(diǎn)位于range2的終點(diǎn)后面,因此第二次比較返回1
復(fù)制范圍
【cloneRange】
可以使用cloneRange()
方法復(fù)制范圍。這個(gè)方法會(huì)創(chuàng)建調(diào)用它的范圍的一個(gè)副本
var newRange = range.cloneRange();
新創(chuàng)建的范圍與原來的范圍包含相同的屬性,而修改它的端點(diǎn)不會(huì)影響原來的范圍
清理范圍
【detach()】
在使用完范圍之后,最好是調(diào)用detach()
方法,以便從創(chuàng)建范圍的文檔中分離出該范圍。調(diào)用detach()
之后,就可以放心地解除對(duì)范圍的引用,從而讓垃圾回收機(jī)制回收其內(nèi)存了。來看下面的例子
range.detach();//從文檔中分離 range = null;//解除引用
在使用范圍的最后再執(zhí)行這兩個(gè)步驟是推薦的方式。一且分離范圍,就不能再恢復(fù)使用了
IE兼容
IE8-瀏覽器不支持DOM范圍。但支持一種類似的概念,即文本范圍(textrange)。文本范圍是IE專有的特性,其他瀏覽器都不支持。顧名思義,文本范圍處理的主要是文本(不一定是DOM節(jié)點(diǎn))。通過<body>、<button>、<input>和<textarea>等這幾個(gè)元素,可以調(diào)用createTextRange()
方法來創(chuàng)建文本范圍。以下是一個(gè)例子
var range = document.body.createTextRange();
像這樣通過document創(chuàng)建的范圍可以在頁(yè)面中的任何地方使用(通過其他元素創(chuàng)建的范圍則只能在相應(yīng)的元素中使用)。與DOM范圍類似,使用IE文本范圍的方式也有很多種
一、簡(jiǎn)單選擇
【findText()】
選擇頁(yè)面中某一區(qū)域的最簡(jiǎn)單方式,就是使用范圍的findText()
方法。這個(gè)方法會(huì)找到第一次出現(xiàn)的給定文本,并將范圍移過來以環(huán)繞該文本。如果沒有找到文本,這個(gè)方法返回false;否則返回true。同樣,仍然以下面的HTML代碼為例
<p id="p1"><b>Hello</b> world!</p>
要選擇"Hello",可以使用下列代碼
var range = document.body.createTextRange(); var found = range.findText("Hello");
執(zhí)行完第二行代碼后,文本"Hello"就被包圍在范圍之內(nèi)了。為此,可以檢査范圍的text屬性來確認(rèn)(這個(gè)屬性返回范圍中包含的文本),或者也可以檢查findText()
的返回值——在找到了文本的情況下返回值為true。
例如:
alert(found); //true alert(range.text); //"Hello"
還可以為findText()
傳入另一個(gè)參數(shù),即一個(gè)表示向哪個(gè)方向繼續(xù)搜索的數(shù)值。負(fù)值表示應(yīng)該從當(dāng)前位置向后搜索,而正值表示應(yīng)該從當(dāng)前位置向前搜索。因此,要査找文檔中前兩個(gè)"Hello"的實(shí)例,應(yīng)該使用下列代碼
var found = range.findText("Hello"); var foundAgain = range.findText("Hello", 1);
【moveToElementText()】
IE中與DOM中的selectNode()方法最接近的方法是moveToElementText()
,這個(gè)方法接受一個(gè)DOM元素,并選擇該元素的所有文本,包括HTML標(biāo)簽。下面是一個(gè)例子
var range = document.body.createTextRange(); var p1 = document.getElementById("p1") range.moveToElementText(p1);
在文本范圍中包含HTML的情況下,可以使用htmlText屬性取得范圍的全部?jī)?nèi)容,包括HTML和文本,如下所示
alert(range.htmlText);
IE的范圍沒有任何屬性可以隨著范圍選區(qū)的變化而動(dòng)態(tài)更新。不過,parentElement()
方法倒是與DOM的 commonAncestorContainer屬性類似
var ancestor = range.parentElement();
這樣得到的父元素始終都可以反映文本選區(qū)的父節(jié)點(diǎn)
二、復(fù)雜選擇
在IE中創(chuàng)建復(fù)雜范圍的方法,就是以特定的增量向四周移動(dòng)范圍。為此,IE提供了4個(gè)方法:move()
、moveStart()
、moveEnd()
和expand()
。這些方法都接受兩個(gè)參數(shù):移動(dòng)單位和移動(dòng)單位的數(shù)量。
其中,移動(dòng)單位是下列一種字符串值
"character":逐個(gè)字符地移動(dòng)
"word":逐個(gè)單詞(一系列非空格字符)地移動(dòng)
"sentence":逐個(gè)句子(一系列以句號(hào)、問號(hào)或嘆號(hào)結(jié)尾的字符)地移動(dòng)
"textedit":移動(dòng)到當(dāng)前范圍選區(qū)的開始或結(jié)束位置
通過moveStart()
方法可以移動(dòng)范圍的起點(diǎn),通過moveEnd()
方法可以移動(dòng)范圍的終點(diǎn),移動(dòng)的幅度由單位數(shù)量指定,如下所示
range.moveStart("word", 2);//起點(diǎn)移動(dòng)2個(gè)單詞 range.moveEnd("character", 1);//終點(diǎn)移動(dòng)1個(gè)字符
使用expand()
方法可以將范圍規(guī)范化。換句話說,expand()
方法的作用是將任何部分選擇的文本全部選中。例如,當(dāng)前選擇的是一個(gè)單詞中間的兩個(gè)字符,調(diào)用expand("word")
可以將整個(gè)單詞都包含在范圍之內(nèi)
而move()方法則首先會(huì)折疊當(dāng)前范圍(讓起點(diǎn)和終點(diǎn)相等),然后再將范圍移動(dòng)指定的單位數(shù)量,如下所示
range.move("character", 5);//移動(dòng)5個(gè)字符
調(diào)用move()
之后,范圍的起點(diǎn)和終點(diǎn)相同,因此必須再使用moveStart()
或moveEnd()
創(chuàng)建新的選區(qū)
三、操作范圍內(nèi)容
在IE中操作范圍中的內(nèi)容可以使用text屬性或pasteHTML()
方法。如前所述,通過text屬性可以取得范圍中的內(nèi)容文本;但是,也可以通過這個(gè)屬性設(shè)置范圍中的內(nèi)容文本。來看一個(gè)例子
var range = document.body.createTextRange(); range.findText("Hello"); range.text = "Howdy";
如果仍以前面的Hello World代碼為例,執(zhí)行以上代碼后的HTML代碼如下
<p id="p1"><b>Howdy</b> world!</p>
[注意]在設(shè)置text屬性的情況下,HTML標(biāo)簽保持不變
【pasteHTML()】
要向范圍中插入HTML代碼,就得使用pasteHTML()
方法,如下所示
var range = document.body.createTextRange(); range.findText("Hello"); range.pasteHTML("<em>Howdy</em>");
執(zhí)行這些代碼后,會(huì)得到如下HTML
<p id="p1"><b><em>Howdy</em></b> world!</p>
不過,在范圍中包含HTML代碼時(shí),不應(yīng)該使用pasteHTML()
,因?yàn)檫@樣很容易導(dǎo)致不可預(yù)料的結(jié)果——很可能是格式不正確的HTML
四、折疊IE范圍
【collapse()】
IE為范圍提供的collapse()
方法與相應(yīng)的DOM方法用法一樣:傳入true把范圍折疊到起點(diǎn),傳入false把范圍折疊到終點(diǎn)。例如:
range.collapse(true); //折疊到起點(diǎn)
可惜的是,沒有對(duì)應(yīng)的collapsed屬性讓我們知道范圍是否已經(jīng)折疊完畢。為此,必須使用boundingWidth屬性,該屬性返回范圍的寬度(以像素為單位)。如果boundingwidth屬性等于0,就說明范圍已經(jīng)折疊了
var isCollapsed = (range.boundingWidth == 0);
此外,還有boundingHeight、boundingLeft和boundingTop等屬性,雖然它們都不像boundingWidth那么有用,但也可以提供一些有關(guān)范圍位置的信息
五、比較IE范圍
【compareEndPoints()】
IE中的compareEndPoints()
方法與DOM范圍的compareBoundaryPoints()
方法類似。這個(gè)方法接受兩個(gè)參數(shù):比較的類型和要比較的范圍。比較類型的取值范圍是下列幾個(gè)字符串值:"StartToStart"、"StartToEnd"、"EndToEnd"和"EndToStart"。這幾種比較類型與比較DOM范圍時(shí)使用的幾個(gè)值是相同的
同樣與DOM類似的是,compareEndPoints()
方法也會(huì)按照相同的規(guī)則返回值,即如果第一個(gè)范圍的邊界位于第二個(gè)范圍的邊界前面,返回-1;如果二者邊界相同,返回0;如果第一個(gè)范圍的邊界位于第二個(gè)范圍的邊界后面,返回1。仍以前面的Hello World代碼為例,下列代碼將創(chuàng)建兩個(gè)范圍,一個(gè)選擇"Hello world!"(包括<b>標(biāo)簽),另一個(gè)選擇"Hello"
var range1 = document.body.createTextRange(); var range2 = document.body.createTextRange(); range1.findText("Hello world!"); range2.findText("Hello"); alert(range1.compareEndPoints("StartToStart", range2)); //outputs 0 alert(range1.compareEndPoints("EndToEnd", range2)); //outputs 1;
由于這兩個(gè)范圍共享同一個(gè)起點(diǎn),所以使用compareEndPoints()
比較起點(diǎn)返回0。而range1的終點(diǎn)在range2的終點(diǎn)后面,所以compareEndPoints()
返回1
IE中還有兩個(gè)方法,也是用于比較范圍的:isEqual()用于確定兩個(gè)范圍是否相等,inRange()
用于確定一個(gè)范圍是否包含另一個(gè)范圍。
下面是相應(yīng)的示例
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
這個(gè)例子使用了與前面相同的范圍來示范這兩個(gè)方法。由于這兩個(gè)范圍的終點(diǎn)不同,所以它們不相等,調(diào)用isEqual返回false。由于range2實(shí)際位于rangel內(nèi)部,它的終點(diǎn)位于后者的終點(diǎn)之前、起點(diǎn)之后,所以range2被包含在rangel內(nèi)部,調(diào)用inRange()
返回true
六、復(fù)制IE范圍
在IE中使用duplicate()
方法可以復(fù)制文本范圍,結(jié)果會(huì)創(chuàng)建原范圍的一個(gè)副本,如下所示
var newRange = range.duplicate();
新創(chuàng)建的范圍會(huì)帶有與原范圍完全相同的屬性
以上是“Javascript中DOM范圍的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
網(wǎng)站欄目:Javascript中DOM范圍的示例分析
本文網(wǎng)址:http://chinadenli.net/article48/pdsshp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供關(guān)鍵詞優(yōu)化、ChatGPT、App設(shè)計(jì)、搜索引擎優(yōu)化、響應(yīng)式網(wǎng)站、商城網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)