JavaScript DOM 范围(Range)对象详解与跨浏览器兼容处理
本文深入解析JavaScript DOM中的Range对象,详细阐述如何将用户选区转换为W3C或IE特有的范围对象。重点讨论Mozilla、Safari、Opera与IE在选区处理上的差异,提供获取用户选区、提取文本内容及创建范围对象的完整代码示例,确保在不同浏览器环境下实现一致的交互效果。
尽管教程会涉及通过程序创建范围对象的方法,但核心重点在于如何将用户手动选取的文本区域转换为符合W3C标准的范围对象或微软特有的文档范围对象。
什么是范围
范围(Range)指的是HTML文档中任意选定的一部分内容。其起始点和结束点可以任意设定,甚至可以是相同的点(即空范围)。最常见的场景是用户手动选中的文本。当用户在页面上选中某段内容时,即可将该选中部分转换为范围对象。此外,程序也可以自动创建并操作范围。
以下面的代码为例。假设用户选中了如下文字:
<h4 id="entry1196"><a
href="http://radar.oreilly.com/archives/2007/03/call_for_a_blog_1.html"
class="external">Call for a Blogger's Code of Conduct</a></h4>
<p>Tim O'Reilly calls for a Blogger Code of Conduct. His proposals are:</p>
<ol>
<li>Take responsibility not just for your own words, but for the
comments you allow on your blog.</li>
<li>Label your tolerance level for abusive comments.</li>
<li>Consider eliminating anonymous comments.</li>
</ol>
你可以将用户选中的内容转换为一个包含该选中范围文本的范围对象(后续章节将详细介绍)。基于这个范围对象,你可以定位到范围的起始点和结束点。如果需要,你可以删除、复制该范围,或者用其他文本甚至HTML代码进行替换。
这是范围对象最简单的示例,因为它仅包含纯文本。接下来我们看一个更复杂的例子:
<h4 id="entry1196"><a
href="http://radar.oreilly.com/archives/2007/03/call_for_a_blog_1.html"
class="external">Call for a Blogger's Code of Conduct</a></h4>
<p>Tim O'Reilly calls for a Blogger Code of Conduct. His proposals are:</p>
<ol>
<li>Take responsibility not just for your own words, but for the
comments you allow on your blog.</li>
<li>Label your tolerance level for abusive comments.</li>
<li>Consider eliminating anonymous comments.</li>
</ol>
另一个范围对象被创建,其中包含了HTML结构。问题的关键在于用户的选中范围跨越了多个HTML元素。去除其他无关内容后,剩余部分如下:
calls for a Blogger Code of Conduct. His proposals are:</p>
<ol>
<li>Take responsibility not just for your own words, but for the
comments you allow on your blog.</li>
<li>Label your toleran
这看起来是一段不完整的HTML代码。幸运的是,所有现代浏览器都会自动进行修正:
<p>calls for a Blogger Code of Conduct. His proposals are:</p>
<ol>
<li>Take responsibility not just for your own words, but for the
comments you allow on your blog.</li>
<li>Label your toleran</li></ol>
正如你所见,浏览器会自动添加最少的必要元素使HTML结构完整。如果你复制这段内容,这些浏览器自动补充的元素也会被一并复制。
浏览器兼容性一览
在继续深入之前,有必要了解浏览器的兼容性情况。主要难点在于存在至少三种不同的范围对象类型,开发者必须对它们都有清晰的认识。
| Module |
Explorer 6/7 |
Firefox 2 | Safari 1.3 | Opera 9 |
| W3C Range | no | yes | yes | yes |
| Mozilla Selection | no | yes | incomplete | yes |
| Microsoft Text Range | yes | no | no | incomplete |
访问用户选区
要处理用户的选择,首先必须能够访问到用户的选区。这立即引出了一个代码分支:IE使用其特有的方法,而其他浏览器则采用Mozilla的方法:
代码如下:
var userSelection;
if (window.getSelection) {
userSelection = window.getSelection();
}
else if (document.selection) { // should come last; Opera!
userSelection = document.selection.createRange();
}在Mozilla、Safari和Opera浏览器中,此时userSelection是一个选择对象(selection object);而在IE中,它是一个文本范围对象(text range object)。这一区别在后续代码中至关重要:IE的文本范围对象与W3C的范围对象及Mozilla的选择对象存在根本性差异,因此每部分代码都需要相应的补充处理。
需要注意分支的判断顺序:Mozilla的Selection检测必须放在前面。因为Opera同时支持这两种方式,如果先使用window.getSelection()读取用户选区,Opera会创建一个选择对象;而随后使用document.selection时,它又会创建一个文本范围对象。
虽然Opera对Mozilla和W3C模式的支持相当不错,但其对IE模式的支持存在缺陷,因此必须将window.getSelection()放在前面进行检测。
userSelection的内容
此时,userSelection既可以是Mozilla的选择对象,也可以是IE的文本范围对象。因此,它可以调用各自支持的所有方法和属性。
接着,Mozilla的选择对象userSelection中保存的是用户选中的纯文本(而非HTML)。获取方式如下:
代码如下:
alert(userSelection) 就会产生:
calls for a Blogger Code of Conduct. His proposals are: Take responsibilitynot just for your own words, but for the comments you allow on your blog.Label your toleran如果想在微软的文本范围对象中得到相同的内容你就要使用:
var selectedText = userSelection;if (userSelection.text) selectedText = userSelection.text;现在selectedText就包含了用户选择的文本。如果你觉得这样的信息足够的话,那么就开始准备后面的工作吧。
从选择对象创建范围对象
很多时候,你需要处理的是代表用户选择范围的范围对象(range object)。在微软模式下,条件已经具备:userSelection本身就是一个文本范围。但在兼容W3C的浏览器中,userSelection仍然只是一个选择对象,此时是时候创建一个与选择对象内容相同的范围对象了。
按照下面这样:
代码如下:
var rangeObject = getRangeObject(userSelection);
function getRangeObject(selectionObject) {
if (selectionObject.getRangeAt)
return selectionObject.getRangeAt(0);
else { // Safari!
var range = document.createRange();
range.setStart(selectionObject.anchorNode,selectionObject.anchorOffset);
range.setEnd(selectionObject.focusNode,selectionObject.focusOffset);
return range;
}
} 理想情况下,我们通过选择对象的getRangeAt()方法来访问W3C范围对象。该方法会在指定位置返回一个范围对象:就像通常情况一样,第一个范围对象的编号是0。(getRangeAt()已经设计好处理多处选择的情况。在那种情况下,你的代码也很简单)
自从创建一个范围
不幸的是Safari1.3不支持getRangeAt()。因此我们需要创建一个与用户选择内容一致的范围对象。这是一个很好的练习机会,可以让你掌握如何创建自己的范围对象。
很明显的从创建一个对象开始:
var range = document.createRange();
现在我们已经有了一个空对象。为了把他插入到文档里面去我们需要使用setStart()函数和setEnd()函数。
这两个方法需要两个参数:
1、在哪个DOM节点上开始或者结束的?
2、从哪个文本偏移上开始或者结束的?文本偏移就是指范围对象的第一个或者最后一个字符的位置。
让我们再来看一遍第二个例子:
href="http://radar.oreilly.com/archives/2007/03/call_for_a_blog_1.html"
class="external">Call for a Blogger's Code of Conduct</a></h4>
<p>Tim O'Reilly calls for a Blogger Code of Conduct. His proposals are:</p>
<ol>
<li>Take responsibility not just for your own words, but for the
comments you allow on your blog.</li>
<li>Label your tolerance level for abusive comments.</li>
<li>Consider eliminating anonymous comments.</li>
</ol>
范围从<p>节点开始,并且文字偏移量是13,因为第14个字符已经是包含在范围里面的了(和通常一样,编号从0开始的)。
范围从<li>结束,偏移量是17,因为第18个字符时范围内的最后一个字符了。
如何创建这个范围对象:
代码如下:
var startPar = [the p node];
var endLi = [the second li node];
range.setStart(startPar,13);
range.setEnd(endLi,17);(注意现在创建的范围对用户不可见,只在浏览器的内部)
现在我们已经创建了一个范围,我们也可以读出他的开始和结束点。startContainer和startOffset决定了范围的开始位置,同样的endContainer和endOffset决定了结束位置。
读取选区的开始和结束位置
不幸的是,你并不知道用户选择了页面哪个部分。所以你需要先读出用户选择的开始和结束的位置:这个必须在选择对象(selection object)里面完成,因为这时候还没有范围对象(range object)。
我们刚刚看到每一个范围对象都有标明他开始和结束位置的四个属性。选择对象也有相似的。当然是另外的名字:anchorNode/anchorOffset代表开始位置,focusNode/focusOffset代表结束位置。
所以读出了选择对象的开始和结束位置之后我们就能创建范围对象了:
代码如下:
range.setStart(selectionObject.anchorNode,selectionObject.anchorOffset);
range.setEnd(selectionObject.focusNode,selectionObject.focusOffset); 待续
现在我们有了范围对象和微软的文本范围对象。以后我们会讲解如何使用它们,并且解决不兼容的问题。
翻译地址:http://www.quirksmode.org/dom/range_intro.html
转载请保留以下信息
作者:北玉(tw:@rehawk)
JavaScript将图片转换为Base64编码的两种途径
2026-11-05 16:43:05
怎么在 Vue 或 React 项目中正确集成 animate.js
2026-11-05 10:23:38
JS注册事件:addEventListener基础语法与参数详解
2026-11-05 08:44:56
JSP和JS的区别:运行环境与服务端/客户端职责解析
2026-11-04 23:34:36
pdf.js 官方下载地址:GitHub Release 获取预编译包
2026-11-04 23:07:27
