通过DOM范围可以选择文档中的某个区域,而不需考虑节点的界限,例如文本高亮的处理就可以使用范围来实现。
1、Range的创建
使用document的createRange来创建一个范围,该方法返回一个Range实例,该实例有很多属性和方法,如下所示:
startContainer:包含范围起点的节点
startOffset:范围起点在startContainer中的偏移量,既节点索引
endContainer:包含范围终点的节点
endOffset:范围终点在endContainer的偏移量,节点索引+1
检测浏览器是否支持范围
document.implementation.hasFeature('Range','2.0') OR
typeof document.createRange === 'function'
创建范围
var range = document.createRange();
//由于IE8及以下浏览器不支持DOM Range,但是支持文本范围(document.body.createTextRange)
var range = document.body.createTextRange();
2、Range的实例方法
假设有一个HTML文档如下所示
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div class="outer" id="outer">
<div class="inner" id="inner1">hello world!</div>
<div class="inner" id="inner2"><span>你好吗</span></div>
</div>
</body>
</html>
选择文档的一部分,可以使用selectNode或者selectNodeContents方法,如下所示
var range = document.createRange();
range.selectNode(inner1);
console.log(range.startOffset);//1 因为空格被当作一个文本节点
---------------------------------------------------
var range = document.createRange();
range.selectNodeContents(outer);
console.log(range.endOffset);//5
//IE8以下
var range = document.body.createTextRange();
range.findText("hello");
console.log(range.text);//hello range.moveToElementText(inner1);
console.log(range.htmlText);
也可以使用setStartBefore、setStartAfter、setEndBefore、setEndAfter等方法来选择文档范围
var range = document.createRange();
range.setStartBefore(inner1);
range.setEndBefore(inner2);
console.log(range.endOffset);//3
还可以使用setStart和setEnd来选择,这两个函数均需要两个参数,一个参照节点,一个偏移量,对于setStart来说,参照节点便是startContainer,而setEnd的参照节点是endContainer
var range = document.createRange();
range.setStart(inner1,0);
range.setEnd(inner1,inner1.childNodes.length);
console.log(range.endOffset);//1
//IE8以下
range.moveStart("word", 2); //起点移动2 个单词
range.moveEnd("character", 1); //终点移动1 个字符
-----------------------------------------
"character":逐个字符地移动。
"word":逐个单词(一系列非空格字符)地移动。
"sentence":逐个句子(一系列以句号、问号或叹号结尾的字符)地移动。
"textedit":移动到当前范围选区的开始或结束位置。
操作选区中内容
1、从文档中删除选区的内容deleteContents和extractContents,他们的区别就是后者会返回删除的文档片段,如下所示
var range = document.createRange();
range.setStart(inner1.firstChild,0);
range.setEnd(inner1.firstChild,5);
//range.deleteContents();
var fragment = range.extractContents();
box.appendChild(fragment);
2、复制选区内容cloneContents,复制出来的只是范围中节点的副本,不是真实的节点
var range = document.createRange();
range.setStart(outer,0);
range.setEnd(outer,outer.childNodes.length);
var fragment = range.cloneContents();
box.appendChild(fragment);
3、向范围中插入内容insertNode或者surroundContents
var range = document.createRange();
range.selectNodeContents(outer);
var span = document.createElement('span');
span.innerText = "我知道了";
range.insertNode(span);//会在范围的开始处插入指定节点
------------------------------------------------------------------
var range = document.createRange();
range.setStart(inner1.firstChild,0);
range.setEnd(inner1.firstChild,5);
var span = document.createElement('span');
span.className = "red";
range.surroundContents(span);
//ie8以下
var range = document.body.createTextRange();
range.findText("Hello");
range.text = "Howdy";
-------------------------------------
range.pasteHTML("<em>Howdy</em>");//类似与range.surroundContents
4、复制Range和清理Range
复制range,使用cloneRange方法,该方法复制出来的是指定范围的副本;使用detach方法把范围从文档中分离,然后解除范围的引用
var range = document.createRange();
range.setStart(inner1.firstChild,0);
range.setEnd(inner1.firstChild,5);
var rangeBak = range.cloneRange();
var fragment = rangeBak.extractContents();
box.appendChild(fragment);
range.detach();
range = null;