老熟女激烈的高潮_日韩一级黄色录像_亚洲1区2区3区视频_精品少妇一区二区三区在线播放_国产欧美日产久久_午夜福利精品导航凹凸

重慶分公司,新征程啟航

為企業(yè)提供網(wǎng)站建設(shè)、域名注冊、服務(wù)器等服務(wù)

Javascript中DOM范圍的示例分析

這篇文章主要介紹Javascript中DOM范圍的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

十多年的海興網(wǎng)站建設(shè)經(jīng)驗(yàn),針對設(shè)計(jì)、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。成都全網(wǎng)營銷推廣的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(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)站推廣”以來,每個客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。

創(chuàng)建范圍

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

[注意]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)建了范圍之后,接下來就可以使用它在后臺選擇文檔中的特定部分。而創(chuàng)建范圍并設(shè)置了其位置之后,還可以針對范圍的內(nèi)容執(zhí)行很多種操作,從而實(shí)現(xiàn)對底層DOM樹的更精細(xì)的控制

每個范圍由一個Range類型的實(shí)例表示,這個實(shí)例擁有很多屬性和方法。

下列屬性提供了當(dāng)前范圍在文檔中的位置信息

  • startContainer:包含范圍起點(diǎn)的節(jié)點(diǎn)(即選區(qū)中第一個節(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就是范圍中第一個子節(jié)點(diǎn)的索引

  • endContainer:包含范圍終點(diǎn)的節(jié)點(diǎn)(即選區(qū)中最后一個節(jié)點(diǎn)的父節(jié)點(diǎn))

  • endOffset:范圍在endContainer中終點(diǎn)的偏移量(與startoffset遵循相同的取值規(guī)則)

  • commonAncestorContainer:startContainer和endContainer共同的祖先節(jié)點(diǎn)在文檔樹中位置最深的那個

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

簡單選擇

要使用范圍來選擇文檔中的一部分,最簡單的方式就是使用selectNode()selectNodeContents() 。這兩個方法都接受一個參數(shù),即一個DOM節(jié)點(diǎn),然后使用該節(jié)點(diǎn)中的信息來填充范圍。其中,selectNode()方法選擇整個節(jié)點(diǎn),包括其子節(jié)點(diǎn);而selectNodeContents()方法則只選擇節(jié)點(diǎn)的子節(jié)點(diǎn)



 
 Hello world!

 

我們可以使用下列代碼來創(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)建的兩個范圍包含文檔中不同的部分:rangl包含

元素及其所有子元素,而rang2包含元素、文本節(jié)點(diǎn)"Hello"和文本節(jié)點(diǎn)"world!"

Javascript中DOM范圍的示例分析

在調(diào)用selectNode()時,startContainer、endContainer和commonAncestorContainer都等于傳入節(jié)點(diǎn)的父節(jié)點(diǎn),也就是這個例子中的document.body。而startoffset屬性等于給定節(jié)點(diǎn)在其父節(jié)點(diǎn)的childNodes集合中的索引(在這個例子中是1——因?yàn)榧嫒軩OM的瀏覽器將空格算作一個文本節(jié)點(diǎn)),endOffset等于startoffset加1(因?yàn)橹贿x擇了一個節(jié)點(diǎn))

在調(diào)用selectNodeContents()時,startContainer、endContainer和commonAncestorContainer等于傳入的節(jié)點(diǎn),即這個例子中的

元素。而startoffset屬性始終等于0,因?yàn)榉秶鷱慕o定節(jié)點(diǎn)的第一個子節(jié)點(diǎn)開始。最后,endOffset等于子節(jié)點(diǎn)的數(shù)量(node.childNodes.length),在這個例子中是2

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

  1. setStartBefore(refNode) :將范圍的起點(diǎn)設(shè)置在refNode之前,因此refNode也就是范圍選區(qū)中的第一個子節(jié)點(diǎn)。同時會將startContainer屬性設(shè)置為refNode.parentNode,將startoffset屬性設(shè)置為refNode在其父節(jié)點(diǎn)的childNodes集合中的索引

  2. setStartAfter(refNode) :將范圍的起點(diǎn)設(shè)置在refNode之后,因此refNode也就不在范圍之內(nèi)了,其下一個同輩節(jié)點(diǎn)才是范圍選區(qū)中的第一個子節(jié)點(diǎn)。同時會將startContainer屬性設(shè)置為refNode.parentNode,將startoffset屬性設(shè)置為refNode在其父節(jié)點(diǎn)的childNodes集合中的索引加1

  3. setEndBefore(refNode) :將范圍的終點(diǎn)設(shè)置在refNode之前,因此refNode也就不在范圍之內(nèi)了,其上一個同輩節(jié)點(diǎn)才是范圍選區(qū)中的最后一個子節(jié)點(diǎn)。同時會將endContainer屬性設(shè)置為refNode.parentNode,將endOffset屬性設(shè)置為refNode在其父節(jié)點(diǎn)的childNodes集合中的索引

  4. setEndAfter(refNode) :將范圍的終點(diǎn)設(shè)置在refNode之后,因此refNode也就是范圍選區(qū)中的最后一個子節(jié)點(diǎn)。同時會將endContainer屬性設(shè)置為refNode.parentNode,將endOffset屬性設(shè)置為refNode在其父節(jié)點(diǎn)的childNodes集合中的索引加1

調(diào)用這些方法時,所有屬性會自動設(shè)置好。不過,要想創(chuàng)建復(fù)雜的范圍選區(qū),也可以直接指定這些屬性的值

復(fù)雜選擇

要創(chuàng)建復(fù)雜的范圍就得使用setStart()setEnd()方法。這兩個方法都接受兩個參數(shù):一個參照節(jié)點(diǎn)和一個偏移量值。對setStart()來說,參照節(jié)點(diǎn)會變成startContainer。而偏移量值會變成startoffset。對于setEnd()來說,參照節(jié)點(diǎn)會變成endContainer,而偏移量值會變成endOffset。可以使用這兩個方法來模仿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);

顯然,要選擇這個節(jié)點(diǎn)(使用range1),就必須確定當(dāng)前節(jié)點(diǎn)(p1)在其父節(jié)點(diǎn)的childNodes集合中的索引。而要選擇這個節(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)是

元素的孫子節(jié)點(diǎn),因?yàn)樗旧硎?b>元素的一個子節(jié)點(diǎn)。因此,p1.firstchild取得的是,而p1.firstchild.firstchild取得的才是這個文本節(jié)點(diǎn)。"world!"文本節(jié)點(diǎn)是

元素的第二個子節(jié)點(diǎn)(也是最后一個子節(jié)點(diǎn)),因此可以使用p1.lastChild取得該節(jié)點(diǎn)。

然后,必須在創(chuàng)建范圍時指定相應(yīng)的起點(diǎn)和終點(diǎn),如下所示

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

因?yàn)檫@個范圍的選區(qū)應(yīng)該從"Hello"中"e"的后面開始,所以在setStart()中傳入helloNode的同時,傳入了偏移量2(即"e"的下一個位置;"H"的位置是0)。設(shè)置選區(qū)的終點(diǎn)時,在setEnd()中傳入worldNode的同時傳入了偏移量3,表示選區(qū)之外的第一個字符的位置,這個字符是”r",它的位置是3(位置0上還有一個空格)。

如下所示

Javascript中DOM范圍的示例分析

由于helloNode和worldNode都是文本節(jié)點(diǎn),因此它們分別變成了新建范圍的startContainer和endContainer。此時startoffset和endOffset分別用以確定兩個節(jié)點(diǎn)所包含的文本中的位置,而不是用以確定子節(jié)點(diǎn)的位置(就像傳入的參數(shù)為元素節(jié)點(diǎn)時那樣)。此時的commonAncestorContainer是

元素,也就是同時包含這兩個節(jié)點(diǎn)的第一個祖先元素

當(dāng)然,僅僅是選擇了文檔中的某一部分用處并不大。但重要的是,選擇之后才可以對選區(qū)進(jìn)行操作

操作范圍內(nèi)容

在創(chuàng)建范圍時,內(nèi)部會為這個范圍創(chuàng)建一個文檔片段,范圍所屬的全部節(jié)點(diǎn)都被添加到了這個文檔片段中。為了創(chuàng)建這個文檔片段,范圍內(nèi)容的格式必須正確有效。在前面的例子中,創(chuàng)建的選區(qū)分別開始和結(jié)束于兩個文本節(jié)點(diǎn)的內(nèi)部,因此不能算是格式良好的DOM結(jié)構(gòu),也就無法通過DOM來表示。但是,范圍知道自身缺少哪些開標(biāo)簽和閉標(biāo)簽,它能夠重新構(gòu)建有效的DOM結(jié)構(gòu)以便對其進(jìn)行操作

對于前面的例子而言,范圍經(jīng)過計(jì)算知道選區(qū)中缺少一個開始的標(biāo)簽,因此就會在后臺動態(tài)加入一個該標(biāo)簽,同時還會在前面加入一個表示結(jié)束的標(biāo)簽以結(jié)束"He"。于是,修改后的DOM就變成了如下所示

Hello world!

另外,文本節(jié)點(diǎn)"world!"也被拆分為兩個文本節(jié)點(diǎn),一個包含"wo",另一個包含"rid!"。最終的DOM樹下圖所示,右側(cè)是表示范圍的文檔片段的內(nèi)容

Javascript中DOM范圍的示例分析

像這樣創(chuàng)建了范圍之后,就可以使用各種方法對范圍的內(nèi)容進(jìn)行操作了

[注意]表示范圍的內(nèi)部文檔片段中的所有節(jié)點(diǎn),都只是指向文檔中相應(yīng)節(jié)點(diǎn)的指針

【deleteContents()】

操作范圍內(nèi)容的第一個方法是deleteContents() ,這個方法能夠從文檔中刪除范圍所包含的內(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í)行以上代碼后,頁面中會顯示如下HTML代碼

Herld!

由于范圍選區(qū)在修改底層DOM結(jié)構(gòu)時能夠保證格式良好,因此即使內(nèi)容被刪除了,最終的DOM結(jié)構(gòu)依舊是格式良好的

【extractContents()】

deleteContents()方法相似,extractContents()方法也會從文檔中移除范圍選區(qū)。但區(qū)別在于,extractContents()會返回范圍的文檔片段。利用這個返回的值,可以將范圍的內(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);

在這個例子中,將提取出來的文檔片段添加到了文檔元素的末尾

[注意]在將文檔片段傳入appendChild()方法中時,添加到文檔中的只是片段的子節(jié)點(diǎn),而非片段本身

Herld!

llo wo

【cloneContents】

還有一種做法是使用cloneContents()創(chuàng)建范圍對象的一個副本,然后在文檔其他地方插入該副本

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);

這個方法與extractContents()非常類似,因?yàn)樗鼈兌挤祷匚臋n片段。它們的主要區(qū)別在于,cloneContents()返回的文檔片段包含的是范圍中節(jié)點(diǎn)的副本,而不是實(shí)際的節(jié)點(diǎn)。執(zhí)行上面的操作后,頁面中的HTML代碼如下所示:

Hello world!

llo wo

[注意]在調(diào)用cloneContents()方法之前,拆分的節(jié)點(diǎn)并不會產(chǎn)生格式良好的文檔片段。換句話說,原始的HTML在DOM被修改之前會始終保持不變

插入范圍內(nèi)容

利用范圍,可以刪除或復(fù)制內(nèi)容,還可以像前面介紹的那樣操作范圍中的內(nèi)容。使用insertNode()方法可以向范圍選區(qū)的開始處插入一個節(jié)點(diǎn)。假設(shè)在前面例子中的HTML前面插入以下HTML代碼

Inserted text

那么可以使用下列代碼:

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代碼,就會得到如下HTML代碼

HeInserted textllo world

[注意]正好被插入到了"Hello"中的"llo"前面,而該位置就是范圍選區(qū)的開始位置。使用這種技術(shù)可以插入一些幫助提示信息,例如在打開新窗口的鏈接旁邊插入一幅圖像

【surroundContents()】

除了向范圍內(nèi)部插入內(nèi)容之外,還可以環(huán)繞范圍插入內(nèi)容,此時就要使用surroundContents()方法。這個方法接受一個參數(shù),即環(huán)繞范圍內(nèi)容的節(jié)點(diǎn)。在環(huán)繞范圍插入內(nèi)容時,后臺會執(zhí)行下列步驟

1、提取出范圍中的內(nèi)容(類似執(zhí)行extractContents() )

2、將給定節(jié)點(diǎn)插入到文檔中原來范圍所在的位置上

3、將文檔片段的內(nèi)容添加到給定節(jié)點(diǎn)中

可以使用這種技術(shù)來突出顯示網(wǎng)頁中的某些詞句,例如下列代碼

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);

以上代碼會給范圍選區(qū)加上一個黃色的背景。得到的HTML代碼如下所示

Hello world!

為了插入,范圍必須包含整個DOM選區(qū),而不能僅僅包含選中的DOM節(jié)點(diǎn)

折疊范圍

所謂折疊范圍,就是指范圍中未選擇文檔的任何部分。可以用文本框來描述折疊范圍的過程。假設(shè)文本框中有一行文本,用鼠標(biāo)選擇了其中一個完整的單詞。然后,單擊鼠標(biāo)左鍵,選區(qū)消失,而光標(biāo)則落在了其中兩個字母之間。同樣,在折疊范圍時,其位置會落在文檔中的兩個部分之間,可能是范圍選區(qū)的開始位置,也可能是結(jié)束位置。下圖展示了折疊范圍時發(fā)生的情形

Javascript中DOM范圍的示例分析

【collapse()】

使用collapse()方法來折疊范圍,這個方法接受一個參數(shù),該參數(shù)是一個布爾值,表示要折疊到范圍的哪一端。參數(shù)true表示折疊到范圍的起點(diǎn),參數(shù)false表示折疊到范圍的終點(diǎn)。要確定范圍已經(jīng)折疊完畢,可以檢査collapsed屬性,如下所示:

range.collapse(true);//折疊到起點(diǎn)
console.log(range.collapsed);//輸出true

檢測某個范圍是否處于折疊狀態(tài),可以幫我們確定范圍中的兩個節(jié)點(diǎn)是否緊密相鄰。例如,對于下面的HTML代碼

Paragraph 1

Paragraph 2

如果不知道其實(shí)際構(gòu)成(比如說,這行代碼是動態(tài)生成的),那么可以像下面這樣創(chuàng)建一個范圍

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

在這個例子中,新創(chuàng)建的范圍是折疊的,因?yàn)閜1的后面和p2的前面什么也沒有

比較范圍

【compareBoundaryPoints()】

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

  1. Range.START_TO_START(0) :比較第一個范圍和第二個范圍的起點(diǎn)

  2. Range.START_TO_END(1) :比較第一個范圍的起點(diǎn)和第二個范圍的終點(diǎn)

  3. Range.END_TO_END⑵ :比較第一個范圍和第二個范圍的終點(diǎn)

  4. Range.END_T0_START(3) :比較第一個范圍的終點(diǎn)和第一個范圍的起點(diǎn)

compareBoundaryPoints()方法可能的返回值如下:如果第一個范圍中的點(diǎn)位于第二個范圍中的點(diǎn)之前,返回-1;如果兩個點(diǎn)相等,返回0;如果第一個范圍中的點(diǎn)位于第二個范圍中的點(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

在這個例子中,兩個范圍的起點(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ù)制范圍。這個方法會創(chuàng)建調(diào)用它的范圍的一個副本

var newRange = range.cloneRange();

新創(chuàng)建的范圍與原來的范圍包含相同的屬性,而修改它的端點(diǎn)不會影響原來的范圍

清理范圍

【detach()】

在使用完范圍之后,最好是調(diào)用detach()方法,以便從創(chuàng)建范圍的文檔中分離出該范圍。調(diào)用detach()之后,就可以放心地解除對范圍的引用,從而讓垃圾回收機(jī)制回收其內(nèi)存了。來看下面的例子

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

在使用范圍的最后再執(zhí)行這兩個步驟是推薦的方式。一且分離范圍,就不能再恢復(fù)使用了

IE兼容

IE8-瀏覽器不支持DOM范圍。但支持一種類似的概念,即文本范圍(textrange)。文本范圍是IE專有的特性,其他瀏覽器都不支持。顧名思義,文本范圍處理的主要是文本(不一定是DOM節(jié)點(diǎn))。通過、