深入了解Javascript中textRange对象使用方法
TextRange对象是动态HTML(DHTML)的高级特性,使用它可以实现很多和文本有关的任务,例如搜索和选择文本。文本范围让您可以选择性的将字符、单词和句子从文档中挑选出来。TextRange对象是在HTML文档将要显示的文本流上建立开始和结束位置的抽象对象。
下面是TextRange的常用属性与方法:
属性
boundingHeight 获取绑定TextRange对象的矩形的高度
boundingLeft 获取绑定TextRange 对象的矩形左边缘和包含TextRange对象的左侧之间的距离
offsetLeft 获取对象相对于版面或由offsetParent属性指定的父坐标的计算左侧位置
offsetTop 获取对象相对于版面或由offsetParent属性指定的父坐标的计算顶端位置
htmlText 获取绑定TextRange对象的矩形的宽度
text 设置或获取范围内包含的文本
方法
moveStart 更改范围的开始位置
moveEnd 更改范围的结束位置
collapse 将插入点移动到当前范围的开始或结尾
move 折叠给定文本范围并将空范围移动给定单元数
execCommand 在当前文档、当前选中区或给定范围上执行命令
select 将当前选择区置为当前对象
findText 在文本中搜索文本并将范围的开始和结束点设置为包围搜索字符串。
使用TextRange对象通常包括三个基本的步骤:
1.创建文本范围
2.设置开始点和结束点
3.对范围进行操作
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
- <HTML>
- <HEAD>
- <TITLE> New Document </TITLE>
- <META NAME="Generator" CONTENT="EditPlus">
- <META NAME="Author" CONTENT="">
- <META NAME="Keywords" CONTENT="">
- <META NAME="Description" CONTENT="">
- <script language="javascript">
- function moveCursor()
- {
- var temp = this.txtNum.value;
- if(isNaN(temp))
- {
- alert("请输入一个数字");
- return;
- }
- var rng = this.txtTest.createTextRange();
- rng.move("character",temp);
- rng.select();
- }
- </script>
- </HEAD>
- <BODY>
- <input type="text" name="txtTest" value="明·罗贯中《三国演义》第二十一回 操曰:“夫英雄者,胸怀大志,腹有良谋,有包藏宇宙之机,吞吐天地之志者也。" size="100"><br>
- 移动光标到第<input type="text" name="txtNum" size="5">个位置
- <input type="button" name="btnMove" value="移动" onclick="moveCursor()">
- </BODY>
- </HTML>
1.createTextRange()
创建一个TextRange对象,BODY、TEXT、TextArea、BUTTON等元素都支持这个方法。该方法返回一个TextRange对象。
2.move("Unit"[,count])
move()方法执行两个操作。首先,方法在前一个结束点的位置重叠当前文档,将这里作为一个插入点;下一步,它将插入点向前或向后移动任意个字符、单词或句子单位。
方法的第一个参数是字符串,它指定的单位有character(字符)、word(词)、sentence(段落)、textedit。 textedit值将插入点移动到整个文本范围的结束处(不需要参数)。如果指定为前三种单位,忽略参数时默认值为1,也可以指定一个整数值来指示单元 数,正数代表向前移动,负数代表向后移动。
注意在move()方法执行后范围仍是重叠的。
3.select()
select()方法选择当前文本范围内的文本,这里的显示光标也必须利用它来实现,因为所谓的"光标"可以理解为边界重合的范围
搜索文本中的字符串
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
- <HTML>
- <HEAD>
- <TITLE> New Document </TITLE>
- <META NAME="Generator" CONTENT="EditPlus">
- <META NAME="Author" CONTENT="">
- <META NAME="Keywords" CONTENT="">
- <META NAME="Description" CONTENT="">
- </HEAD>
- <BODY>
- <textarea name="txtBox" rows="7" cols="50" id="txtBox">
- 菊花台 (满城尽带黄金甲主题曲)
- 歌手:周杰伦 专辑:依然范特西
- 你的泪光 柔弱中带伤
- 惨白的月弯弯 勾住过往
- 夜太漫长 凝结成了霜
- 是谁在阁楼上冰冷的绝望
- 雨轻轻淌 朱红色的窗
- 我一生在纸上 被风吹乱
- 梦在远方 化成一缕霞
- 随风飘散 你的模样
- 菊花惨淡地伤 你的笑容已泛黄
- 花落人断肠 我心事静静淌
- 北风乱夜未央 你的影子剪不断
- 徒留我孤单在湖面生霜
- </textarea><br>
- <input type="text" value="输入要查询的内容" id="txtFind">
- <input type="button" value="查找下一个" onclick="findText(txtFind.value)">
- <script language="javascript">
- var rng = txtBox.createTextRange();
- function findText(str)
- {
- if(str=="")
- return;
- //定义一个变量,作为moveStart()函数的偏移量,即开始点跳过选择文本
- var num = 0;
- if(document.selection)
- num = document.selection.createRange().text.length;
- //每次调用函数,结束点都为末尾,而开始点是跳过选择文本后的新开始点
- rng.moveStart("character",num);
- rng.moveEnd("character",txtBox.value.length);
- //搜索到后选择文本
- if(rng.findText(str))
- rng.select();
- //搜索到最后的范围还是找不到,则提示搜索完毕,并重新恢复rng最初的范围(否则无法执行新搜索)
- if(rng.text!=str)
- {
- alert("搜索完毕");
- rng = txtBox.createTextRange();
- }
- }
- </script>
- </BODY>
- </HTML>
上面的例子演示了利用moveStart()和moveEne()方法选择范围,出现的几个方法的说明如下:
4.moveStart("Unit"[,count])与moveEnd("Unit"[,count])
moveStart()与moveEnd()方法类似于move()方法,默认情况下开始点为容器第一个字符、结束点为最后一个字符
我们可以修改上面的selectText()函数来证明:
function selectText()
{
var rng = txtBox.createTextRange();
rng.moveStart("character",1);
rng.moveEnd("character",-1);
rng.select();
}
将开始点向前移动一个字符、结束点向后移动一个字符,运行后可以看到选择的范围是除第1个字符和最后1个字符的整个文本范围。
5.collapse([Boolean])
可以用collapse()方法把文本范围从当前尺寸重叠成字符间的单个插入点。collapse()方法的可选参数是Boolean值,它指出范围是在当前范围的开始点重合,还是结束点重合。默认值为true,在开始点重合:
5.findText("searchString"[,searchScope,flags])
TextRange对象最有用的方法之一是findText()方法,其默认行为是从开始点到结束点浏览文本范围,搜索一个不区分大小写的字符串 匹配。如果在范围中发现一个实例,范围的开始点和结束点就放到这个文本中,方法返回true;否则返回false,开始点和结束点都不动。方法仅搜索显示 文本,而任何标记或属性都不会被搜索。
可选参数searchScope是一个整数值,它指示从开始点的字符数,值越大,包含在搜索范围的文本越多;负值将迫使搜索操作从当前开始点向后搜索。
可选参数flag用来设置搜索是否区分大小写,或者是否仅匹配整个单词。参数是整数值,它用按位组合的数学方法计算单个值,这些值能容纳一个或多 个设置。匹配整个单词的值为2;匹配大小写的值为4;如果只想匹配一项,则只提供希望的值就够了,但对于两种行为,要用位操作XOR操作符(^操作符)使 值为6。
findText()方法最常用的应用包括范围中的查找和替换操作,以及格式化一个字符串的实例,因为搜索通常以范围的当前开始点开始,所以再次 查询要将开始点移到范围中匹配文本的末尾(如示例3),移动后才能使findText()继续浏览剩下的文本范围,来查找另一个匹配。可以使用 collapse(false)方法迫使开始点移动第一个匹配的范围的结束点。所以示例3的findText()函数也可以修改为:
<script language="javascript">
var rng = txtBox.createTextRange();
function findText(str)
{
if(str=="")
return;
if(rng.findText(str))
{
rng.select();
rng.collapse(false);
}
//搜索到最后的范围还是找不到,则提示搜索完毕,并重新恢复rng最初的范围(否则无法执行新搜索)
else
{
alert("搜索完毕");
rng = txtBox.createTextRange();
}
}
</script>
6.parentElement()
parentElement()方法返回包含文本范围容器的引用
获得光标选中文本的DOM对象
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
- <HTML>
- <HEAD>
- <TITLE> New Document </TITLE>
- <META NAME="Generator" CONTENT="EditPlus">
- <META NAME="Author" CONTENT="">
- <META NAME="Keywords" CONTENT="">
- <META NAME="Description" CONTENT="">
- <script>
- function getParElem()
- {
- var rng = document.selection.createRange();
- var container = rng.parentElement();
- //alert(container.getAttribute("id")||container.getAttribute("value")||container.getAttribute("type"));
- alert(container.tagName);
- }
- </script>
- </HEAD>
- <BODY>
- 这是只属于Body的文本
- <div>这是包含在div里的文本</div>
- <p>这是包含在p里面的文本</p>
- <div><strong>这是包含在div->strong里的文本</strong></div>
- <input type="button" value="选择文本后点击" onClick="getParElem()">
- </BODY>
- </HTML>
TextRange对象的属性破败:物业 描述htmlText 为选定的文本范围返回HTML片段。 这是一个只读属性。<H1>This is a sample page.</H1> <P>This is some sample text.</P>text 设置或检索范围内所载的案文。 这是一个读写属性,这意味着你可以改变以及检索其当前值。This is a sample page. This is some sample text.boundingWidth 检索范围的矩形的文本范围的宽度。305boundingHeight 检索范围的矩形的文本范围的高度。74boundingLeft 检索左边坐标矩形范围的文本范围。12boundingTop 检索顶端坐标矩形范围的文本范围。17offsetLeft 检索左边坐标矩形范围的文本范围。12此属性是不完全一样boundingLeft 例如,如果你把一<DIV STYLE="position: absolute; left: 200">...</DIV>示例代码<DIV STYLE="position: absolute; left: 200">...</DIV>的定义,此属性将评估为212。offsetTop 检索顶端坐标矩形范围的文本范围。17此属性是不完全一样boundingLeft 例如,如果你把一<DIV STYLE="position: absolute; top: 200">...</DIV>示例代码<DIV STYLE="position: absolute; top: 200">...</DIV>的定义,此属性将评估为217。该TextRange对象还包括许多方法。 以下是最有用的清单:法 描述collapse([ start ]) 将插入点移动到开始(默认)或现有案文范围的结束(如果false参数指定)。expand( unit ) 扩大了范围,使部分单位完全控制。 此方法返回true ,如果它成功地扩大了范围,或false除外。 unit可以是以下字符串值之一:"character"扩展字符。"word"扩展一个字。 一个字是由空格或其他空白字符终止字符集合。"sentence"扩大一个句子。 句子是由一个标点符号,一个字终止收集,如一个时期。"textedit"扩展附上整个范围。 换句话说,这个范围扩大到其原始尺寸。下面的脚本创建一个部分为当前选择的TextRange对象,并确保任何文字部分由封闭的范围变得完全封闭的范 围:var range = document.selection.createRange(); range.expand("word");duplicate() 返回父文本范围(该方法的TextRange对象)重复。parentElement() 为给定的文本范围返回父元素。 父元素是最小的元素包围的范围文本。inRange( otherRange ) 返回一个布尔值指示是否一个范围(参数)是在另一个(对象中)。isEqual( otherRange ) 返回一个布尔值指示是否一个范围(参数)等于另一个(对象)。scrollIntoView([ start ]) 使对象滚动到,调整它在上方或窗口的底部。 如果start参数是false ,该对象的底部可见在窗口的底部。 否则,该对象滚动到默认的顶部。setEndPoint( type , range ) 树立了一个范围根据另一范围的端点一个端点。 该type参数是一个字符串,指定端点转移什么,什么样的父范围应该取代端点。 它接受下列字符串之一"StartToEnd"或"EndToEnd" 第二个参数, range是从该文本范围源端点的意见。compareEndPoints( type , range ) 如果家长确定文本范围(该方法的TextRange对象),并作为参数( range )有着共同的端点所指定的。 此方法返回-1(小于),0(等于),或1(大于)。 该type参数必须"StartToEnd"或"EndToEnd" 正如你所看到的,它描述了端点进行比较。 注意:术语“终结”并不一定是指文本范围的最后位置。 它可以是无论是第一个位置,或者是最后一个,在你指定的type参数而定。select() 使得在页面等于当前的文本范围的活动选择。上表列出了一个TextRange对象的最重要的一般方法。 下表列出了各种运动方法。 在选择一个TextRange对象,可以将其启动和使用范围运动的方法终点。 请注意,它们实际上并不移到网页上的任何文字。 它们只是移动的幅度本身的界限,从而影响了,这是由文本范围选定的文本。 下面是这些方法概要:法 描述move( unit [, count ]) 变化的开始和结束的文本范围点,将不同的文字。 这种方法移动文本范围,而不是文本本身。 第一个参数接受下列字符串之一:"character"移动一个或多个字符。"word"移动一个或多个词。 一个字是由空格或其他空白字符终止字符集合。"sentence"移动一个或多个句子。 句子是由一个标点符号,一个字终止收集,如一个时期。"textedit"在开始和结束原始文本范围移动。第二个参数, count ,指定的单位数目移动(正或负)。 默认值为1,如果省略。 此方法返回实际的数字移动。moveStart( unit [, count ]) 此方法是为move()相同的move()但它只是移动范围的开始位置。 它改变了移动范围的开始位置范围的范围。moveEnd( unit [, count ]) 此方法是为move()相同的move()但它只是移动范围的结束位置。 它改变了移动范围的结束位置,范围的范围。pasteHTML( htmlText ) 指定的HTML粘贴到给定的文本范围的文本。 案文完全取代任何以前的文本的范围和HTML元素。 此方法不能用于文件时加载。 另外请注意,插入的文本和HTML元素应符合给定的文本范围。 例如,试图将其粘贴到一个文本范围不包含一个表可能造成的方法插入一个TABLE元素表格单元格。请记住,文字幅度,不是在Internet Explorer 4.0x中,Mac版的支持。 这些方法和属性只是相关的Internet Explorer 4.0x中Win32版本。 这页的文字只讨论范围的基础,因为这列重点的选择,而不是文本范围。 更多关于TextRange对象的资料,请参考微软的文档 。 在本专栏的下一部分,我们将采取在过的外观浏览器的选择处理。 |
Range对象
Range对象表示文档的连续范围区域,如用户在浏览器窗口中用鼠标拖动选中的区域。
dom标准Range对象
http://www.w3school.com.cn/xmldom/dom_range.asp
在ie中使用TextRange对象
http://www.hbcms.com/main/dhtml/objects/obj_textrange.html
range对象常用的建立方法
在开发中除了上述文档中的标准建立方法,大多如下方式建立
标准dom:
var range=window.getSelection().getRangeAt(0);
ie:
var range=document.selection.createRange();
注意:标准dom是从window中获取selection对象,而ie是从document对象中获取。
标准dom range对象(以下称dom rang)和ie的TextRange对象(以下称TextRange),在操作模式上有很大区别,可以说dom range是基于dom结构控制的,TextRange是基于文本节点字节控制的,阅读下面示例会更好理解这二者的操作模式。以下所说的range对象是 指在html结构中进行选择和更改(designMode=on contentEditable=true状态下)操作,在textarea中的操作比这简单,不是当前的研究环境。
range对象的具体方法和属性请查看上边列出的相关api文档,下面对实际开发过程中常用功能讲解
1.区域选择 获取区域中文本
TextRange的区域选择
TextRange对象主要使用以下方法控制区域的选择:moveStart moveEnd move
这三个函数使用相同的参数语法:fn(sUnit [, iCount])
第一个参数是指移动的单位,可以使用的参数:character(字符)、word(词)、sentence(段落)、textedit(整个编辑区)
第二个参数指移动的数量单位,负数向所在位置之前移动,正数向所在位置之后移动。
在实际开发中一般使用character,其他几个参数在中文环境和html编辑时,和预想位置有偏差。
例1:TextRange选择光标前4个字符
代码如下:
var rg=document.selection.createRange();
rg.moveStart("character",-4);
rg.select();//显式选择文本区域,不调用此函数也可以获得选择的内容
var text=rg.text;//获得选择的文本
var htmlText=rg.htmlText;//获得选择文本的html代码
用rg.htmlText获得选择文本的html代码,但获得结果不尽人意,
如:<b>aaaa</b>bb ,当选择aabb段时,.htmlTex返回的是<b>aa</b>bb而不是aa</b>bb
其他常用位置控制函数:
collapse: 合并前后选择点,true为开始点,false为结尾点。
moveToPoint: 移动光标到坐标 moveToBookmark: 移动到书签。
dom range的区域选择
dom range对象选择区域主要以dom节点为为坐标,所有边界移动和区域选择函数都是以dom节点为参照的
setEnd()setStart()是控制范围的前边界点和后边界点位置的函数,
有两个参数,第一个参数是dom节点,第二个参数是偏移量,这个参数和TextRange.move中不同,是相对于dom节点的偏移量。
如:有文字节点node1 nodeValue是aaabbbccc,setStart(node1,3)则设置开始位置在字符a、b之间
那如何像例1一样选择光标前4个字符呢,这需要了解dom range对象的几个属性:
endContainer 包含范围的结束点的 dom节点。
endOffset endContainer 中的结束点位置。
startContainer 包含范围的开始点的 dom节点。
startOffset startContainer 中的开始点位置。
例2:dom range选择光标前4个字符
代码如下:
var rg=window.getSelection().getRangeAt(0);
rg.setStart(rg.startContainer,rg.startOffset-4);//获得当前range strat所在节点和偏移量,计算后作为参数
//在调用setStart后即显式选择,与TextRange不同
var text=rg.toString();//获得选择文本
rg.collapse(false);//collapse函数与TextRange.collapse相同
例2中range选择范围操作适用于单一的文本内容,如果是html内容就需要进一步计算才能正确得到,总的来看dom range在复杂dom结 构中进行相对范围选择是比较麻烦的。
另外,dom range没有直接的方法获得选择内容的html代码。在html可编辑状态下可以通过surroundContents()方法用一个span之类的标 签包裹住内容后再通过innerHTML获得内容,但是在选择范围边界点在html开始和结束标签内时 (如:<a>123</a>边界点在a标签内)会抛出一个异常。
以下是测试用完整代码,包含例1和例2的代码和一个测试用html可编辑区。
代码如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
</HEAD>
<BODY>
<SCRIPT LANGUAGE="JavaScript">
<!--
window.onload=function(){
var iframeContent="";
var divContent="";
var divChange=false;
var iframeChange=false;
var $=function(s){return document.getElementById(s);}
$("ifram_div").innerHTML+='<div id="infoIframe">iframe</div><iframe id="youretextarea" style="height:200px;width:99%;" class="_editbox"></iframe>';
var fw=$("youretextarea").contentWindow;
var f=fw.document;
f.designMode = 'On';
f.contentEditable = true;
f.open();
f.writeln('<html><style>p{margin:0px;padding:0px;}body{margin:0px;padding:0px;font:16/18px Arial;}</style><body><b>aaaa</b><u>bbbb</u>cccddd</body></html>');
f.close();
if(f.attachEvent){
f.attachEvent("onkeyup",fun1);
}else{
fw.addEventListener("keyup",fun1,true);
}
function fun1(){
if(f.selection){
var rg=f.selection.createRange();
rg.moveStart("character",-4);
//rg.select();//显式选择文本区域,不调用此函数也可以获得选择的内容
var text=rg.text;//获得选择的文本
var htmlText=rg.htmlText;//获得选择文本的html代码
alert(text);
}else{
var rg=fw.getSelection().getRangeAt(0);
rg.setStart(rg.startContainer,rg.startOffset-4);//获得当前range strat所在节点和偏移量,计算后作为参数
//在调用setStart后即显式选择,与TextRange不同
var text=rg.toString();//获得选择文本
rg.collapse(false);//collapse函数与TextRange.collapse相同
alert(text);
}
}
}
//-->
</SCRIPT>
<div id="ifram_div"></div>
</BODY>
</HTML>
2.插入文本
TextRange插入文本
使用TextRang插入文本比较简单,直接调用pasteHTML()方法就可以直接插入html代码。
Dom Range插入文本
使用Dom Range插入文本相对复杂一些,Dom Range对象使用insertNode()方法实现插入,但是insertNode是在Range的开始位置插入一 个节点,参数是一个节点而不是字符串,我们可以通过插入文本节点实现,如果使用document.createTextNode建立文本节点,文本中的 HTML标记会自动转换,但空格是个特例,并不会自动转换为 ,这使我在开发代码缩进时很头疼,最后解决的办法,是使用Rang.createContextualFragment,这个方法虽然在文档中没有找到, 但测试多个浏览器都支持此方法,此方法返回的是一个DocumentFragment对
象。以下是示例代码:
例3:
Js代码
代码如下:
var rg = window.getSelection().getRangeAt(0);
var fragment = rg.createContextualFragment(str);
rg.insertNode(fragment);
这段代码虽然实现插入了文本,但是光标位置却在插入文本之前,因为“insertNode是在Range的开始位置插入一 个节点”,接下来我们实现光标的控制,这需要设置Range对象的位置,并更新Selection对象的Range,代码如下:
例4:
Js代码
代码如下:
var selection=window.getSelection();
var rg=selection.getRangeAt(0);
var fragment = rg.createContextualFragment(str);
var oLastNode = fragment.lastChild; //获得DocumentFragment的末尾位置
rg.insertNode(fragment);
rg.setEndAfter(oLastNode);//设置末尾位置
rg.collapse(false);//合并范围至末尾
selection.removeAllRanges();//清除range
selection.addRange(rg);//设置range
以下是一个代码缩进功能的部分代码作为示例:按tab键时会在当前位置,插入4个空格,解决在编辑时不能输入tab的问题。实际应用中的功能包括多行缩进和自动缩进。
代码如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
</HEAD>
<BODY>
<SCRIPT LANGUAGE="JavaScript">
<!--
window.onload=function(){
var iframeContent="";
var divContent="";
var divChange=false;
var iframeChange=false;
var $=function(s){return document.getElementById(s);}
$("ifram_div").innerHTML+='<div id="infoIframe">iframe</div><iframe id="youretextarea" style="height:200px;width:99%;" class="_editbox"></iframe>';
var fw=$("youretextarea").contentWindow;
var f=fw.document;
f.designMode = 'On';
f.contentEditable = true;
f.open();
f.writeln('<html><style>p{margin:0px;padding:0px;}body{margin:0px;padding:0px;font:16/18px Arial;}</html>');
f.close();
if(f.attachEvent){
f.attachEvent("onkeydown",fun1);
}else{
fw.addEventListener("keydown",fun1,true);
}
function fun1(e){
ee=e||window.event;
var code=e.charCode||e.keyCode;
var strTab=" ";
if(code==9){//tab键
if(f.selection){//ie
e.returnValue=false;//取消浏览器默认动作 ie
var rg=f.selection.createRange();
rg.pasteHTML(strTab);
}else{
e.preventDefault();//取消浏览器默认动作
var selection=fw.getSelection();
var rg=selection.getRangeAt(0);
var fragment = rg.createContextualFragment(strTab);
var oLastNode = fragment.lastChild; //获得DocumentFragment的末尾位置
rg.insertNode(fragment);
rg.setEndAfter(oLastNode);//设置末尾位置
rg.collapse(false);//合并范围至末尾
selection.removeAllRanges();//清除range
selection.addRange(rg);//设置range
}
}
}
}
//-->
</SCRIPT>
<div id="ifram_div"></div>
</BODY>
</HTML>
3.替换
综合介绍的选择和插入的方法可完成替换功能,TextRange比较简单pasteHTML方法会替换原来Range选中的文本,Dom Range的insertNode不会删除原range选中内容,需要调用deleteContents()方法先删除选择内容。