惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

L
LINUX DO - 最新话题
Cyberwarzone
Cyberwarzone
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Security Archives - TechRepublic
Security Archives - TechRepublic
S
Securelist
V2EX - 技术
V2EX - 技术
www.infosecurity-magazine.com
www.infosecurity-magazine.com
P
Privacy & Cybersecurity Law Blog
Spread Privacy
Spread Privacy
N
News and Events Feed by Topic
H
Heimdal Security Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
大猫的无限游戏
大猫的无限游戏
L
LangChain Blog
爱范儿
爱范儿
阮一峰的网络日志
阮一峰的网络日志
G
GRAHAM CLULEY
L
Lohrmann on Cybersecurity
G
Google Developers Blog
Recorded Future
Recorded Future
H
Hacker News: Front Page
Application and Cybersecurity Blog
Application and Cybersecurity Blog
The GitHub Blog
The GitHub Blog
量子位
V
V2EX
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Vercel News
Vercel News
H
Help Net Security
Know Your Adversary
Know Your Adversary
Forbes - Security
Forbes - Security
T
Threatpost
S
SegmentFault 最新的问题
Hugging Face - Blog
Hugging Face - Blog
T
Threat Research - Cisco Blogs
人人都是产品经理
人人都是产品经理
Project Zero
Project Zero
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
罗磊的独立博客
C
Check Point Blog
P
Palo Alto Networks Blog
Google DeepMind News
Google DeepMind News
Last Week in AI
Last Week in AI
L
LINUX DO - 热门话题
Apple Machine Learning Research
Apple Machine Learning Research
C
Cybersecurity and Infrastructure Security Agency CISA
A
Arctic Wolf

张鑫旭-鑫空间-鑫生活

1分钟速度了解text-align match-parent声明 « 张鑫旭-鑫空间-鑫生活 光标的形状也能设置了,就是CSS caret-shape属性 « 张鑫旭-鑫空间-鑫生活 pretext与文字四面环绕效果的实现 « 张鑫旭-鑫空间-鑫生活 JSON.rawJSON方法的作用是什么? « 张鑫旭-鑫空间-鑫生活 如何使用CSS判断鼠标从哪个方向进入元素? « 张鑫旭-鑫空间-鑫生活 借助mediabunny纯JS实现视频水印、剪裁、合成等功能 « 张鑫旭-鑫空间-鑫生活 务必谨慎使用JS WeakRef弱引用 « 张鑫旭-鑫空间-鑫生活 CSS六边形头像的实现与蜂巢布局 « 张鑫旭-鑫空间-鑫生活 CSS corner-shape与背景底纹技术 « 张鑫旭-鑫空间-鑫生活 浅学WebTransport API:下一代Web双向通信技术 « 张鑫旭-鑫空间-鑫生活 HTML dialog元素新支持了closedBy属性 « 张鑫旭-鑫空间-鑫生活 HTML interestfor属性与悬停popover交互效果 « 张鑫旭-鑫空间-鑫生活 CSS3模拟window7炫酷界面效果展示 « 张鑫旭-鑫空间-鑫生活 图片旋转+剪裁js插件(兼容各浏览器) « 张鑫旭-鑫空间-鑫生活 纯js无图片无外链CSS图片幻灯片播放插件 « 张鑫旭-鑫空间-鑫生活 CSS border三角、圆角图形生成技术简介 « 张鑫旭-鑫空间-鑫生活 CSS “渐进增强”在web制作中常见应用举例 « 张鑫旭-鑫空间-鑫生活 让IE6/IE7/IE8浏览器支持CSS3属性 « 张鑫旭-鑫空间-鑫生活 jQuery – 高亮动态显示页面HTML代码插件 « 张鑫旭-鑫空间-鑫生活 翻译 – 逐渐消失的Flash网站 « 张鑫旭-鑫空间-鑫生活 CSS reset的重新审视 – 避免样式重置 « 张鑫旭-鑫空间-鑫生活 新浪微博插入话题后部分文字选中的js实现 « 张鑫旭-鑫空间-鑫生活 JavaScript实现http地址自动检测并添加URL链接 « 张鑫旭-鑫空间-鑫生活 CSS实现兼容性的渐变背景(gradient)效果 « 张鑫旭-鑫空间-鑫生活 CSS content内容生成技术以及应用 « 张鑫旭-鑫空间-鑫生活 CSS gradient渐变之webkit核心浏览器下的使用 « 张鑫旭-鑫空间-鑫生活 CSS渐变之CSS3 gradient在Firefox3.6下的使用 « 张鑫旭-鑫空间-鑫生活 区分IE8/IE7/IE6及其他浏览器-CSS “\9″hack « 张鑫旭-鑫空间-鑫生活 CSS实现跨浏览器兼容性的盒阴影效果 « 张鑫旭-鑫空间-鑫生活 CSS3&HTML5各浏览器支持情况一览表 « 张鑫旭-鑫空间-鑫生活 翻译 – CSS Sprites:实用技术还是生厌之物? « 张鑫旭-鑫空间-鑫生活 纯CSS实现易拉罐3D滚动效果 « 张鑫旭-鑫空间-鑫生活 纯CSS实现侧边栏/分栏高度自动相等 « 张鑫旭-鑫空间-鑫生活 CSS+JavaScript实现页面不同布局的切换 « 张鑫旭-鑫空间-鑫生活 JavaScript实现最简单的拖拽效果 « 张鑫旭-鑫空间-鑫生活 自己写的无图片版jQuery zxxbox弹出框插件 « 张鑫旭-鑫空间-鑫生活 中国古代道家思想与网页重构的思考 « 张鑫旭-鑫空间-鑫生活 让所有浏览器支持HTML5 video视频标签 « 张鑫旭-鑫空间-鑫生活 纯CSS实现各类气球泡泡对话框效果 « 张鑫旭-鑫空间-鑫生活 JS HEX十六进制与RGB, HSL颜色的相互转换 « 张鑫旭-鑫空间-鑫生活 CSS实现兼容性的渐变、高光等文字效果 « 张鑫旭-鑫空间-鑫生活 去除冗余 – 精简您的CSS样式代码 « 张鑫旭-鑫空间-鑫生活 对overflow与zoom”清除浮动”的一些认识 « 张鑫旭-鑫空间-鑫生活 jQuery Pagination Ajax分页插件中文详解 « 张鑫旭-鑫空间-鑫生活 absolute绝对定位的非绝对定位用法 « 张鑫旭-鑫空间-鑫生活 网页布局思想浅议-淘宝新版首页为实例 « 张鑫旭-鑫空间-鑫生活 回流与重绘:CSS性能让JavaScript变慢? « 张鑫旭-鑫空间-鑫生活 CSS float浮动的深入研究、详解及拓展(二) « 张鑫旭-鑫空间-鑫生活 CSS float浮动的深入研究、详解及拓展(一) « 张鑫旭-鑫空间-鑫生活 60个极富创造性的震撼的电影海报设计 « 张鑫旭-鑫空间-鑫生活 jQuery Lightbox(balupton版)图片展示插件讲解 « 张鑫旭-鑫空间-鑫生活 博客内嵌flash音乐播放器代码、下载与使用 « 张鑫旭-鑫空间-鑫生活 CSS3 animate实现图片墙3D翻转效果 « 张鑫旭-鑫空间-鑫生活 图片旋转效果的一些研究、jQuery插件及实例 « 张鑫旭-鑫空间-鑫生活 CSS3 border-image详解、应用及jQuery插件 « 张鑫旭-鑫空间-鑫生活 jQuery-两款不同原理的圆角插件讲解 « 张鑫旭-鑫空间-鑫生活 页面可用性之outline轮廓外框的一些研究 « 张鑫旭-鑫空间-鑫生活 CSS3 transition实现超酷图片墙动画效果 « 张鑫旭-鑫空间-鑫生活 HTML CSS列表元素ul,ol,dl的研究与应用 « 张鑫旭-鑫空间-鑫生活 jQuery图片文本滚动切换插件jCarousel中文翻译与详解 « 张鑫旭-鑫空间-鑫生活 酷酷的jQuery鼠标悬停图片放大切换显示效果 « 张鑫旭-鑫空间-鑫生活 IE6下z-index犯癫不起作用bug的初步研究 « 张鑫旭-鑫空间-鑫生活 checkbox复选框的一些深入研究与理解 « 张鑫旭-鑫空间-鑫生活 jQuery之使用slideToggle实现垂直下拉菜单 « 张鑫旭-鑫空间-鑫生活 jQuery-innerfade内部列表自动淡入淡出插件 « 张鑫旭-鑫空间-鑫生活 jQuery-火焰灯效果导航菜单 « 张鑫旭-鑫空间-鑫生活 IE下css bug集合-翻译自haslayout.net « 张鑫旭-鑫空间-鑫生活 翻译-IE7/8@font-face嵌入字体与文字平滑 « 张鑫旭-鑫空间-鑫生活 jQuery-马化腾产品设计与用户体验的一些技术实现 « 张鑫旭-鑫空间-鑫生活 像素的世界及其在web开发制作中的应用 « 张鑫旭-鑫空间-鑫生活 css行高line-height的一些深入理解及应用 « 张鑫旭-鑫空间-鑫生活 CSS实现圆角六色渐变自适应按钮详解 « 张鑫旭-鑫空间-鑫生活 我熟知的三种三栏网页宽度自适应布局方法 « 张鑫旭-鑫空间-鑫生活 jQuery照片图像剪裁插件Jcrop中文翻译详解 « 张鑫旭-鑫空间-鑫生活 Ajax Upload多文件上传插件翻译及中文演示 « 张鑫旭-鑫空间-鑫生活 告别图片—使用字符实现兼容性的圆角尖角效果beta版 « 张鑫旭-鑫空间-鑫生活 大小不固定的图片、多行文字的水平垂直居中 « 张鑫旭-鑫空间-鑫生活 jQuery boxy弹出层对话框插件中文演示及讲解 « 张鑫旭-鑫空间-鑫生活 JavaScript实现新浪微博文字放大显示动画效果 « 张鑫旭-鑫空间-鑫生活 翻译:让网络更快一些——最小化浏览器中的回流(reflow) « 张鑫旭-鑫空间-鑫生活 jQuery之addClasas与removeClass使用实例 « 张鑫旭-鑫空间-鑫生活 关于Google圆角高光高宽自适应按钮及其拓展 « 张鑫旭-鑫空间-鑫生活 JavaScript实现图片幻灯片滚动播放动画效果 « 张鑫旭-鑫空间-鑫生活 jQuery-鼠标经过显示大图并跟随鼠标效果插件 « 张鑫旭-鑫空间-鑫生活 关于gif图片(或png8)杂边锯齿的问题 « 张鑫旭-鑫空间-鑫生活 对html与body的一些研究与理解 « 张鑫旭-鑫空间-鑫生活 鲜为人知的一个解决兼容性问题的利器——小数 « 张鑫旭-鑫空间-鑫生活 搜狐白社会似iphone短信对话框效果的优化 « 张鑫旭-鑫空间-鑫生活 关于文字内容溢出用点点点(…)省略号表示 « 张鑫旭-鑫空间-鑫生活 jquery之append与insertBefore使用实例 « 张鑫旭-鑫空间-鑫生活 jQuery之图片关联伸缩效果 « 张鑫旭-鑫空间-鑫生活 jquery之图片左右切换动画效果 « 张鑫旭-鑫空间-鑫生活 jQuery之replace字符串替换实现不同尺寸图片切换 « 张鑫旭-鑫空间-鑫生活 jQuery-实现图片的放大镜显示效果 « 张鑫旭-鑫空间-鑫生活 jQuery-单击文字或图片内容放大显示效果插件 « 张鑫旭-鑫空间-鑫生活 reflection.js-实现图片投影倒影效果js插件 « 张鑫旭-鑫空间-鑫生活 jQuery-很酷的弹出层效果js插件 « 张鑫旭-鑫空间-鑫生活 复选框单选框与文字对齐问题的研究与解决 « 张鑫旭-鑫空间-鑫生活 css margin的相关属性,问题及应用 « 张鑫旭-鑫空间-鑫生活 IE6下png背景不透明问题的综合拓展 « 张鑫旭-鑫空间-鑫生活
JS Range HTML文档/文字内容选中、库及应用介绍 « 张鑫旭-鑫空间-鑫生活
张鑫旭,zhangxinxu · 2011-04-14 · via 张鑫旭-鑫空间-鑫生活

by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=1591

一、前面的些话

本文的内容基本上是基于“区域范围对象(Range objects)”这个概念来说的。这个玩意,可以让你选择HTML文档的任意部分,并可以拿这些选择的信息做你想做的事情。其中,最常见的Range是用户用鼠标选择的内容(user selection)。

本文有不少篇幅就是讲如何将用户的这种选择转换为W3C RangeMicrosoft Text Range对象

二、什么是Range?

所谓”Range”,是指HTML文档中任意一段内容。一个Range的起始点和结束点位置任意,甚至起始点和结束点可以是一样的(也就是空Range)。最常见的Range是用户文本选择范围(user text selection)。当用户选择了页面上的某一段文字后,你就可以把这个选择转为Range。当然,你也可以直接用程序定义Range。

例如下面这个模样的例子:

2011-04-12
负责调查切尔诺贝利核事故对人与环境造成影响的俄科学家亚布罗科夫博士指出,因福岛核电站使用的燃料较切尔诺贝利核电站多,且有反应堆使用了含有高毒性的钚的燃料,因此"福岛核电站事故可能会比切尔诺贝利带来更严重的后果"。

上面选中状态的那些文字就可以转换成Range对象(下面会详细讲述)。通过Range对象你可以找到Range的起始点和结束点,如果你实在有心,还可以删除或是复制这些内容,或是用其他文字替换,甚至是简单的HTML。

上面的例子可以说是最简单的Range对象的例子,因为其只包含了文字。而实际上,Range对象也是可以包含HTML代码内容的,例如下面这个示例:

<time>2011-04-12</time>
<p>据日本广播协会电视台12日报道,日本经济产业省原子能安全保安院决定将福岛第一核电站核泄漏事故等级提高至7级。这使日本核泄漏事故等级与苏联切尔诺贝利核电站核泄漏事故等级相同。</p>
<p>负责调查切尔诺贝利核事故对人与环境造成影响的俄科学家亚布罗科夫博士指出,因福岛核电站使用的燃料较切尔诺贝利核电站多,且有反应堆使用了含有高毒性的钚的燃料,因此"福岛核电站事故可能会比切尔诺贝利带来更严重的后果"。</p>

同样的,Range对象被创建,且包含HTML,现在的问题是选择的内容正好跨过了楚河和汉界(跨标签),如果就单纯的论选择的内容的话,应该如下:

泄漏事故等级与苏联切尔诺贝利核电站核泄漏事故等级相同。</p>
<p>负责调查切尔诺贝

显然,上面的HTML属于1级残废,基本无效。然而幸运的是,所有的浏览器都会自动调整HTML片段使其有效,就像变成下面这样:

<p>泄漏事故等级与苏联切尔诺贝利核电站核泄漏事故等级相同。</p>
<p>负责调查切尔诺贝</p>

可以看到,浏览器自动补全了一定数目的HTML来让Range有效。如果你复制或是移动Range,你所复制或移动的HTML内容一定是有效的。

三、浏览器的兼容性

在真正操刀JavaScript之前我们需要大致知道Range对象的浏览器兼容性情况。实际上,问题是比较麻烦的,因为至少有3种类似Range对象,且你有必要全部理解。先展示详细的兼容性情况表:

支持:支持不支持:不支持部分支持:部分支持

1. W3C Range
W3C Range
  Explorer 6/7 Firefox 2 Safari 1.3 Opera 9
cloneContents() 不支持 支持 部分支持 支持
cloneRange() 不支持 支持 支持 支持
collapse() tbd tbd tbd tbd
collapsed 不支持 支持 支持 支持
commonAncestorContainer 不支持 支持 支持 支持
compareBoundaryPoints() 不支持 支持 支持 支持
comparePoint() – Mozilla 扩展 不支持 支持 不支持 不支持
createContextualFragment() – Mozilla 扩展 不支持 支持 支持 支持
deleteContents() 不支持 支持 支持 支持
detach() 不支持 支持 支持 支持
endContainer 不支持 支持 支持 支持
endOffset 不支持 支持 支持 部分支持
extractContents() 不支持 支持 支持 支持
insertNode() 不支持 支持 支持 支持
isPointInRange() – Mozilla 扩展 不支持 支持 不支持 不支持
selectNode() 不支持 支持 支持 支持
selectNodeContents() 不支持 支持 支持 支持
setEnd() 不支持 支持 支持 支持
setEndAfter() 不支持 支持 支持 支持
setEndBefore() 不支持 支持 支持 支持
setStart() 不支持 支持 支持 支持
setStartAfter() 不支持 支持 支持 支持
setStartBefore() 不支持 支持 支持 支持
startContainer 不支持 支持 支持 支持
startOffset 不支持 支持 支持 部分支持
surroundContents() 不支持 支持 支持 支持

说明:
cloneContents()的用法类似docFrag = rangeObject.cloneContents()Range对象内容被克隆同时被添加到文档片段上,并返回自身。但是在Safari下有个问题,即如果选择范围是空,将会返回null而不是空的文档片段。可以通过类似docFrag = rangeObject.cloneContents() || document.createDocumentFragment()这样的代码修复。

deleteContents()处,Range内容会被永久删除,无返回值。

endContainer指用户选择内容结尾处的容器节点。通常是文本节点。

extractContents()用法docFrag = rangeObject.extractContents()。从DOM树上剪切Range对象并返回文档片段。该片段可以粘贴到页面上。

startContainer指用户选择内容起始处的容器节点。通常是文本节点。

startOffset在Opera浏览器下,在选择内容为空的时候返回0

2. Mozilla Selection
Mozilla Selection
  Explorer 6/7 Firefox 2 Safari 1.3 Opera 9
addRange() 不支持 支持 不支持 支持
anchorNode 不支持 支持 支持 支持
anchorOffset 不支持 支持 支持 部分支持
collapse() tbd tbd tbd tbd
collapseToEnd() 不支持 支持 支持 支持
collapseToStart() 不支持 支持 支持 支持
containsNode() 不支持 支持 不支持 支持
deleteFromDocument() 不支持 支持 不支持 支持
extend() 不支持 支持 不支持 支持
focusNode 不支持 支持 支持 支持
focusOffset 不支持 支持 支持 部分支持
getRangeAt() 不支持 支持 不支持 支持
isCollapsed 不支持 支持 支持 支持
rangeCount 不支持 支持 不支持 支持
removeAllRanges() 不支持 支持 不支持 支持
removeRange() 不支持 支持 不支持 支持
selectAllChildren() 不支持 支持 不支持 支持
selectionLanguageChange() 不支持 支持 不支持 支持

说明:
anchorNode用法为userSelection.anchorNode。指用户选择内容起始处的容器节点。通常是文本节点。

anchorNode在Opera浏览器下,在选择内容为空的时候返回0

focusNode用法为userSelection.focusNode。指用户选择内容结尾处的容器节点。通常是文本节点。

focusOffset在Opera浏览器下,在选择内容为空的时候返回0

getRangeAt()用法为rangeObject = userSelection.getRangeAt(0),作用是将Mozilla Selection转换为W3C Range。

3. Microsoft TextRange
Microsoft TextRange
  Explorer 6/7 Firefox 2 Safari 1.3 Opera 9
boundingHeight 支持 不支持 不支持 不支持
boundingLeft 支持 不支持 不支持 不支持
boundingTop 支持 不支持 不支持 不支持
boundingWidth 支持 不支持 不支持 不支持
collapse() tbd tbd tbd tbd
compareEndPoints() 支持 不支持 不支持 不支持
duplicate() 支持 不支持 不支持 支持
expand() 支持 不支持 不支持 不支持
findText() 支持 不支持 不支持 不支持
htmlText 支持 不支持 不支持 不支持
move() 支持 不支持 不支持 支持
moveEnd() 支持 不支持 不支持 支持
moveStart() 支持 不支持 不支持 支持
moveToElementText() 支持 不支持 不支持 支持
moveToPoint() 支持 不支持 不支持 不支持
offsetLeft 支持 不支持 不支持 不支持
offsetTop 支持 不支持 不支持 不支持
parentElement() 支持 不支持 不支持 支持
pasteHTML() 支持 不支持 不支持 不支持
scrollIntoView() 支持 不支持 不支持 不支持
select() 支持 不支持 不支持 支持
text 支持 不支持 不支持 支持

说明:
htmlText用法为htmlString = userSelection.htmlText。返回字符串,为TextRange的HTML内容,相当于innerHTML。只读。

pasteHTML(),当粘贴HTML到一个文本节点时,该文本节点自动分隔。

text用法为string = userSelection.text。返回字符串,为TextRange的文本内容,相当于innerText。可读/写。

4. 总的兼容性
总的兼容性
  Explorer 6/7 Firefox 2 Safari 1.3 Opera 9
W3C Range

详述

不支持 支持 支持 支持
Mozilla Selection

详述

不支持 支持 部分支持 支持
Microsoft Text Range

详述

支持 不支持 不支持 部分支持

说明:

  • W3C Range对象是唯一官方指定。基本上其是将Range作为包含DOM的文档片段。
  • Mozilla Selection对象显得有些多余,其存在是为了向后兼容Netscape 4。其类似于W3C Range对象,也是基于DOM树的。
  • Microsoft Text Range对象跟上面两个就是郭德纲和玄彬的区别了,因为其是基于字符串的。事实上,Text Range包含的字符串是很难一下子跳变成DOM节点的。

总的来说,Mozilla Selection对象就是个打酱油的命,仅有的闪光点能够直接将用户选择任何内容变成完全Range对象以及一些额外的方法或是属性可以向后兼容Netscape 4。但是不幸的是除了IE浏览器外的其他浏览器都支持此Selection对象。

四、获得用户选择内容

婆婆妈妈的解释就免了,直接看相关代码:

var userSelection;
if (window.getSelection) { //现代浏览器
    userSelection = window.getSelection();
} else if (document.selection) { //IE浏览器 考虑到Opera,应该放在后面
    userSelection = document.selection.createRange();
}

由于兼容性的问题,IE浏览器吃IE的包子,其他浏览器吃Mozilla的馒头。

在Mozilla、Safari、Opera下上面的userSelection是个Selection对象,而在IE下则是Text Range对象。这种差异会影响到你后面的脚本:Internet Explorer的Text Ranges完全不同于Mozilla的Selection或是W3C的Range对象,你需要分别为IE和其他浏览器写两套不同的脚本。

需要注意脚本书写的顺序:Mozilla Selection需放在前面。原因在于Opera支持两种对象,如果你使用window.getSelection()去读取用户选择的内容,Opera会创建一个Selection对象;而使用document.selection则会创建一个Text Range对象

因为Opera支持Mozilla Selection和W3C Range非常好,但是其对Microsoft Text Range的支持却差强人意。所以显然优先考虑标准浏览器,即使用window.getSelection()

五、userSelection的内容

userSelection变量现在的内容要么是Mozilla Selection要么就是Microsoft Text Range对象。因此它允许访问定义在对象上的全部方法和属性。

Mozilla Selection对象包含用户选择的文本内容,如下操作:

console.log(userSelection.toString())

虽然格式并不是字符串,但是在现代浏览器下还是会弹出类似下面的内容:

泄漏事故等级与苏联切尔诺贝利核电站核泄漏事故等级相同。负责调查切尔诺贝

为了从Microsoft Text Range 对象上获得同样的信息,你需要使用userSelection.text。为了读取旋转的文字,可以使用类似下面代码:

var selectedText = userSelection;
if (userSelection.text) {
    selectedText = userSelection.text;
}

现在selectedText就包含了用户所选中的文字了。

我们组合一下,完整获取用户选择文本代码如下:

var userSelection, selectedText = '';
if (window.getSelection) { //现代浏览器
    userSelection = window.getSelection();
    selectedText = userSelection.toString();
} else if (document.selection) { // 老IE浏览器
    userSelection = document.selection.createRange();
    selectedText = userSelection.text;
}

您可以狠狠地点击这里:获取用户所选文字demo

例如在IE7浏览器下,选中一段文字再点击demo页面上的测试按钮,就会有类似下面的弹出内容:

获取用户选中的文字截图

input输入框IE下选择文本的获取
如果是<input>或者<textarea>输入框,在支持getSelection()方法的浏览器中,selectedText值是空字符串,需要使用其他方法获取。如下:

// input指输入框DOM元素
selectedText = input.value.slice(input.selectionStart, input.selectionEnd);

六、从Selection对象创建Range对象

在IE浏览器下,userSelectionText Range,在现代浏览器下,userSelection仍然是Selection对象,要想同样创建和Selection对象内容一样的Range对象可以使用类似下面代码:

var getRangeObject = function(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;
    }
}
var rangeObject = getRangeObject(userSelection);

理想情况下,我们通过Selection对象的getRangeAt()方法就可以得到W3C Range对象。此方法可以返回给定索引值的range对象。通常情况下,在JavaScript中第一个Range的索引值是0

使用程序创建Range

Safari 1.3不支持getRangeAt(),因此我们要想兼顾此浏览器,需要使用其他的方法创建新的Range对象。显然,显示创建一个对象:

var range = document.createRange();

上面的一行代码创建了一个空的Range,为了插入内容,我们需要通过setStart()setEnd()方法定义起止点。

这两个方法需要两个参数:
1. Range起止的DOM节点
2. Range起止的文本偏移。该偏移指选中文字第一个字符和最后一个字符在文本节点中的位置。

setStart()的两个参数属性为startContainerstartOffsetsetEnd()两个参数属性为endContainerendOffset

以下面这个例子举例:

<p>男人,即使到了50岁,也千万不要碰超过26岁还没有结婚的女人。她可以是离婚,丧偶等等的,但是绝对不能是没有结婚。超过了26岁没有结婚,这种女人一般心理变态,不然就是有严重问题。市场很少犯错。即使它犯了错,那被你捡到宝的概率也很小。</p>
<p>婚姻市场未来的变化将会是很有趣的问题,而且对未来大陆经济的走势也有举足轻重的影响,对于行业的分布,经济的整体效率有决定性的影响。</p>

<ol>
    <li>为什么是26这个准确的数字?</li>
    <li>找骂帖</li>
    <li>言论是对的,在100年前,lz穿越了而已。</li>
</ol>

此处Range开始于第二个<p>节点,结束与第一个<li>节点。(通常文本节点的第一个字符的索引是0。)

由于<p>节点处的文字偏移值是8, <li>节点处的偏移是5,因而有:

var startP = [the p node];
var endLi = [the second li node];
range.setStart(startP, 8);
range.setEnd(endLi, 5);

读取起止选中内容

上面提到了setStart(startContainer, startOffset)以及setEnd(endContainer, endOffset)。考虑到实际情况,你很难准确知道用户选择的文字的起始位置,所以,上面一板一眼赋予偏移值的方法显然有很大的局限性。好在任何(看参见上面的兼容性表格)Range对象有4个属性是用来定义选择内容起止点的,这4个属性与Selection对象相似,但是却是不同的名称:anchorNode/anchorOffset定义选择的起始,focusNode/focusOffset定义结束。

因此,上面的脚本创建选区可以使用如下代码实现:

range.setStart(selectionObject.anchorNode,selectionObject.anchorOffset);
range.setEnd(selectionObject.focusNode,selectionObject.focusOffset);

Safari的多虑

现在已经是2011年了,释小龙都有绯闻了,Safari 5已经出来好些日子了。所以,如果仅仅是为了兼顾低版本的Safari而去使用程序创建Range,我觉得是一点必要都没有。尤其在我们这个神奇的国度上,首先使用Safari就少,低版本的就少之又少,Safari老早就已经支持getRangeAt()了,Chrome浏览器也是如此。

您可以狠狠地点击这里:Safari下getRangeAt测试demo

选择demo页面中的任意一部分文字,然后点击测试按钮,在较新版本的Safari浏览器下就会出现类似下图的结果:

Safari下getRangeAt弹出

所以,在当前环境下,要想将Selection对象转换成Range对象,直接如下代码就OK了(完整版):

var userSelection, rangeObject;
if (window.getSelection) { 
    //现代浏览器
    userSelection = window.getSelection();
} else if (document.selection) { 
    //IE浏览器 考虑到Opera,应该放在后面
    userSelection = document.selection.createRange();
}

//Range对象
rangeObject = userSelection;
if (userSelection.getRangeAt) {
    //现代浏览器
    rangeObject = userSelection.getRangeAt(0);
}

七、rangy – JavaScript Range&Selection库

项目地址:http://code.google.com/p/rangy/

就在几天前,rangy更新到了版本1.1,作者还新更新了四五个示意的页面,展示了相关的API,方法和属性等。虽然如此,由于实例较少,还是让人很难知道此JavaScript库如何使用。这里就举几个简单的例子示意下。//zxx:此插件非压缩达115K,个人觉得有些庞大,在实际项目中的应用价值不大

示例1,获取用户选中的文字:

您可以狠狠地点击这里:rangy获取用户选中文字demo

选中部分文字点击按钮,会有如下弹出(截自Firefox3.6):

rangy获取用户选中文字

相关JavaScript代码如下:

var sel = rangy.getSelection();
alert(sel.toString());

示例2,给选中文字添加背景

您可以狠狠地点击这里:文字选中添加背景图demo

选中页面上一段文字,然后失去焦点,就会看到文字后面有了个美女背景图,如下截图,截自IE7浏览器:

完整JavaScript代码如下:

<script src="//www.zhangxinxu.com/study/201104/rangy/rangy-core.js"></script>
<script src="//www.zhangxinxu.com/study/201104/rangy/rangy-cssclassapplier.js"></script>
<script>
    var cssApplier;
    window.onload = function() {
        rangy.init();
        cssApplier = rangy.createCssClassApplier("selectClass", true); 
        document.body.onmouseup = function() {
            cssApplier.toggleSelection();
        };
    };
</script>

八、实际的应用

微博之插入话题

差不多去年这个时候,自己折腾过JS 文本域光标处添加文字并选中的内容,也是拿的新浪微博示例的,文章是“新浪微博插入话题后部分文字选中的js实现”,但是去年这篇文章多实现的话题插入效果是比较弱的:
1. 选中普通文字不能作为话题插入
2. 话题只能插在文本域最后二不是光标处
3. 默认文字的话题可以重复插入

所以,趁这个机会,正好把微博之插入话题这个功能完善下。

您可以狠狠地点击这里:微博插入话题的效果实现demo

欢迎输入内容,点击测试。大致会有类似下面的效果(截自Chrome):

源代码有些高度,为了节约篇幅,这里就不展示出来了,您可以在demo页面中看到完整的CSS/HTML/JS代码。不过JS部分半封装,您要是有兴趣可以在外面包裹一个函数使其插件化,我是懒得再去折腾了。

九、结语相关

对于Range相关的知识即使到现在都是半生不熟的,所以文章的内容更多的算是翻译性质的内容。自己并没有从深入理解的基础上很浅显地剖析相关知识点,文章很多地方会显得不怎么通俗易懂。

文中多展示的Range等兼容性表格的数据都是N年前的,还是Safari 1.3时代的数据,老的牙都掉了,实用价值大打折扣,不过可以告知的是先前现代浏览器所不支持的个别属性现早就支持了。

跌跌撞撞,滚滚爬爬。文章难免有表述不准确的地方,欢迎指正。也欢迎提交相关的脚本的bug。

参考文章及相关页面:

  1. Introduction to Range
  2. W3C DOM Compatibility – Range
  3. rangy – A cross-browser JavaScript range and selection library
  4. Reveal a Background Image upon Text Selection

本文为原创文章,转载请注明来自张鑫旭-鑫空间-鑫生活[http://www.zhangxinxu.com]
本文地址: http://www.zhangxinxu.com/wordpress/?p=1591

(本篇完)