时间:2020-11-15 13:50:51 | 栏目:JavaScript代码 | 点击:次
例如下面这个模样的例子:
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对象,且你有必要全部理解。先展示详细的兼容性情况表:
支持:
不支持:
部分支持:
| Explorer 6/7 | Firefox 2 | Safari 1.3 | Opera 9 | |
|---|---|---|---|---|
| cloneContents() | ![]() |
![]() |
![]() |
![]() |
| cloneRange() | ![]() |
![]() |
![]() |
![]() |
| collapse() | tbd | tbd | tbd | tbd |
| collapsed | ![]() |
![]() |
![]() |
![]() |
| commonAncestorContainer | ![]() |
![]() |
![]() |
![]() |
| compareBoundaryPoints() | ![]() |
![]() |
![]() |
![]() |
| comparePoint() ?C Mozilla 扩展 | ![]() |
![]() |
![]() |
![]() |
| createContextualFragment() ?C Mozilla 扩展 | ![]() |
![]() |
![]() |
![]() |
| deleteContents() | ![]() |
![]() |
![]() |
![]() |
| detach() | ![]() |
![]() |
![]() |
![]() |
| endContainer | ![]() |
![]() |
![]() |
![]() |
| endOffset | ![]() |
![]() |
![]() |
![]() |
| extractContents() | ![]() |
![]() |
![]() |
![]() |
| insertNode() | ![]() |
![]() |
![]() |
![]() |
| isPointInRange() ?C 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。
| 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。
| 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。可读/写。
| 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对象。
婆婆妈妈的解释就免了,直接看相关代码:
源代码有些高度,为了节约篇幅,这里就不展示出来了,您可以在demo页面中看到完整的CSS/HTML/JS代码。不过JS部分半封装,您要是有兴趣可以在外面包裹一个函数使其插件化,我是懒得再去折腾了。
对于Range相关的知识即使到现在都是半生不熟的,所以文章的内容更多的算是翻译性质的内容。自己并没有从深入理解的基础上很浅显地剖析相关知识点,文章很多地方会显得不怎么通俗易懂。
文中多展示的Range等兼容性表格的数据都是N年前的,还是Safari 1.3时代的数据,老的牙都掉了,实用价值大打折扣,不过可以告知的是先前现代浏览器所不支持的个别属性现早就支持了。
跌跌撞撞,滚滚爬爬。文章难免有表述不准确的地方,欢迎指正。也欢迎提交相关的脚本的bug。
原创文章,转载请注明来自张鑫旭-鑫空间-鑫生活