为了让开发人员更方便控制页面,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();
复制代码
新建立的范围会带有与原范围彻底相同的属性。
😋😋😋 好了,基本知识就是这些,在这里和你们说拜拜啦~