IE6-8中通过TextRange记录用户选中范围的方法

作者:像素猫

时间:2026-10-27

浏览:452

本文详细讲解在IE6至IE8浏览器中,如何利用createTextRange和setEndPoint方法记录并重现用户选中的文本范围。针对跨节点选择和单节点内重复字符定位的问题,提供了基于htmlText属性和moveEnd偏移计算的解决方案,并附带完整代码示例。

文章目录

IE6-8中TextRange基础应用

在与同事探讨一个有趣的技术问题时,涉及记录用户在网页上选中的内容。在Firefox和IE9等现代浏览器中,可以使用W3C DOM2级事件中的createRange方法实现,此处不再赘述。主要挑战在于IE6、IE7和IE8版本,这些旧版浏览器仅支持通过createTextRange来选中特定区域。假设我们已经知道用户选择的起始元素及其偏移量,以及结束元素及其偏移量,就可以通过以下示例代码,使用JavaScript将用户选中的内容进行标记。


具体实现代码如下:

 
<head>
<script>
function mark() {
var b= document.getElementById ("b");
var b1= document.getElementById ("b1");
var b2= document.getElementById ("b2");
var a1 = document.body.createTextRange();
a1.moveToElementText(b);
a1.moveStart('character',17);
var a2 = document.body.createTextRange();
a2.moveToElementText(b1);
a2.moveEnd('character',-2);
a1.setEndPoint ("EndToEnd",a2);
a1.select();
}</script>
</head>
<body>
<div id="b">The <b>contents</b> of the <i>source</i> element.</div>
<div id="b1">The <b>contents</b> of the <i>source</i> element.</div>
<div id="b2">The <b>contents</b> of the <i>source</i> element.</div>
<button onclick="mark();">Mark</button>
</body>

从上述代码可以看出,在IE6、IE7和IE8环境下,若需关联多个元素的选择范围,必须创建两个TextRange对象:一个用于定义起始节点及偏移量,另一个用于定义结束节点及偏移量。随后,通过调用a1.setEndPoint方法将这两个范围关联起来,从而完成选中区域的标记。

参考文档:http://help.dottoro.com/ljgbbkjf.php

http://msdn.microsoft.com/en-us/library/ms535872%28VS.85%29.aspx

获取选中范围的挑战与策略

上述示例基于已知开始和结束位置的情况。那么,如何获取用户自行选中的区域(热区)的起始和结束节点及其偏移量呢?

经过查阅MSDN文档,发现可利用的属性有限,主要包括:

textRange.parentElement:返回选中热区的父节点,有助于确定大致范围。

boundingLeft和offsetLeft:用于获取热区的左侧偏移距离。

boundingTop和offsetTop:用于获取热区的顶部偏移距离。

text:返回选中的纯文本内容,htmlText:返回选中的HTML内容。

然而,这些属性并未直接提供索引(index)或起始节点等详细信息。

若需通过位置计算,可以通过每行的line-height累加高度。对于单个节点,还需计算节点的height、padding和margin。

若计算左侧偏移,则需考虑font-size、margin、padding和letter-spacing。通过CSS计算,可得出大致位置。

接着,结合text和htmlText与附近元素的文本内容进行比对,从而确定索引坐标。

这样,基本可以确定起始和结束节点以及偏移量。

不过,这种方法的成本较高,不知各位是否有更好的办法或黑客技巧?

==================================================================================

随后再次查看htmlText方法,发现一个有趣的现象。以之前的例子为例,htmlText返回如下结果:

 

<DIV id=src>he <I>source</I> element.</DIV>


<DIV id=src1>The <B>contents</B> of the <I>source</I> element</DIV>

可以看到起始节点的tagName以及选中的内容。通过去除首尾的HTML标签,并使用正则表达式判断这段HTML代码在之前parent.innerHTML中的位置,即可获取偏移量。因此,无需通过判断offset的方式,也能获取起始和结束节点及偏移量。

这样,在IE6、IE7和IE8中,即可记录用户任意选中的内容的起始节点、结束节点及偏移量。

 =============================================================

但这样做仍有一个唯一缺点:对于单个字符或重复出现的单词,仍需通过css的offsetLeft等属性,判断距离以确定是否选中了正确的字符。不知各位有何建议?

===============================================================

单节点内重复字符的定位方案

今早灵光一现,突发奇想,解决了无需通过offsetTop和left判断单个节点内部重复字符偏移量的问题。

具体代码如下:

具体实现代码如下:

 
<head>
<script>
function mark() {
var selection=document.selection.createRange();
if(selection.text.length==0){
return;
} 
var textLength=event.srcElement.innerText.length;
var oldSelectionParent=selection.parentElement();
do{
selection.moveEnd("character",1);
}while(selection.parentElement()==oldSelectionParent);
selection.moveEnd("character",-1);
alert(textLength - selection.text.length);
} 
function load(){
document.body.onmouseup=mark;
//document.body.onmousedown=mark;
} 
</script>
</head>
<body onload="load()">
<div> 飞 a a a a 飞飞飞飞飞a飞 a a a </div>
</body>

其原理是利用在一个节点内部不断偏移1个字符,直到到达底部或顶部,通过计算偏移量来解决问题。对于单个元素内的热区,其parentElement()返回即为自身;若跨多个节点,之后返回的parentNode即为父节点。通过这种变化,可判断是否移动到该节点文本的尽头,从而计算偏移量。






总结而言,通过htmlText属性可解决多节点选中热区的定位问题;对于单节点内部重复字符,可通过文末代码部分解决。这样,在IE下记录光标选中位置和复现的方法就较为完善。




============================================

全兼容解决方案参考

去kissy群咨询后,得知承玉已编写全兼容的位置获取代码,链接如下:


https://www.jb51.net/article/28120.htm

代码地址:http://lite-ext.googlecode.com/svn/trunk/lite-ext/playground/range/ie.html

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章