ホームページ  >  記事  >  ウェブフロントエンド  >  JS範囲のHTMLドキュメント/テキストコンテンツの選択、ライブラリとアプリケーションの紹介_JavaScriptスキル

JS範囲のHTMLドキュメント/テキストコンテンツの選択、ライブラリとアプリケーションの紹介_JavaScriptスキル

WBOY
WBOYオリジナル
2016-05-16 18:06:481296ブラウズ
一、前面的些话
本文的内容基本上是基于“区域范围对象(Range objects)”这个概念来说的。这个玩意,可以让你选择HTML文档的任意部分,并可以拿这些选择的信息做你想做的事情。其中,最常见的Range是用户用鼠标选择的内容(user selection)。

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

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

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

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

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

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

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

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

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

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

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

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

三、浏览器的兼容性

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

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

1. W3C 範囲
W3C 範囲
  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 セレクション
Mozilla セレクション
  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对象Guo Degang と Xuan Bin の違いは、文字列に基づいているため、上記の 2 つです。実際、Text Range に含まれる文字列が一度に DOM ノードにジャンプすることは困難です。

一般に、Mozilla Selection对象 は単なる混乱にすぎません。唯一の優れている点は、ユーザーが選択したコンテンツを直接完全な Range对象 に変換できることと、いくつかの追加メソッドまたは属性が Netscape 4 と下位互換性があることです。 。しかし残念ながら、IE 以外の他のブラウザはこの Selection对象 をサポートしています。

4. ユーザーが選択したコンテンツを取得します

義母の説明は必要ありません。関連するコードを見てください:

コードをコピーしてください コードは次のとおりです。

var userSelection;
if (window.getSelection) { //最新のブラウザ
userSelection = window.getSelection(); else if (document.selection) ) { //IE ブラウザは Opera に対して、最後に配置する必要があるとみなします。
userSelection = document.selection.createRange();
}

互換性の問題により、IE ブラウザはIE およびその他のブラウザを利用します。 Mozilla 蒸しパンを食べます。

上記の userSelection は、Mozilla、Safari、Opera では Selection オブジェクトですが、IE では Text Range オブジェクトです。この違いは、後続のスクリプトに影響します。 Internet Explorer のテキスト範囲は、Mozilla の Selection オブジェクトや W3C の Range オブジェクトとはまったく異なります。IE およびその他のブラウザー用に 2 つの異なるスクリプト セットを作成する必要があります。

スクリプトを記述する順序に注意する必要があります。Mozilla 選択を最初に配置する必要があります。その理由は、Opera が 2 種類のオブジェクトをサポートしているためです。 window.getSelection() を使用してユーザーが選択したコンテンツを読み取ると、Opera は Selection オブジェクトを作成し、document.selection を使用すると Text Range オブジェクトを作成します。

Opera は Mozilla Selection と W3C Range を非常によくサポートしていますが、Microsoft Text Range のサポートは満足のいくものではありません。したがって、明らかに標準ブラウザ、つまり window.getSelection() の使用が優先されます。


5. userSelection の内容
userSelection 変数の現在の内容は、Mozilla Selection オブジェクトまたは Microsoft Text Range オブジェクトです。したがって、オブジェクトに定義されているすべてのメソッドとプロパティへのアクセスが許可されます。

Mozilla Selection オブジェクトには、次のようにユーザーが選択したテキスト コンテンツが含まれます。

alert(userSelection)
形式は文字列ではありませんが、次のようなポップアップが表示されます。以下は最新のブラウザでも表示されます 内容:

漏洩事故のレベルはソ連のチェルノブイリ原子力発電所の核漏洩事故のレベルと同じです。チェルノブイリの調査を担当
Microsoft Text Range オブジェクトから同じ情報を取得するには、userSelection.text を使用する必要があります。回転されたテキストを読み取るには、次のようなコードを使用できます:

コードをコピー コードは次のとおりです:
var selectedText = userSelection;
if (userSelection.text) {
selectedText = userSelection.text;
}

現在 selectedText にはテキストが含まれていますユーザーが選択したもの。

ここをクリックできます: ユーザーが選択したテキスト デモを取得します。

たとえば、IE7 ブラウザでは、テキストの一部を選択し、デモ ページ上のテスト ボタンをクリックします。ポップアップの内容:

JS範囲のHTMLドキュメント/テキストコンテンツの選択、ライブラリとアプリケーションの紹介_JavaScriptスキル
6. Selection オブジェクトから Range オブジェクトを作成します IE ブラウザーでは、userSelection はモダンでは Text Range です。ブラウザでは、userSelection は引き続き Selection オブジェクトです。Selection オブジェクトと同じ内容を持つ Range オブジェクトを作成するには、次のようなコードを使用できます。

コードをコピー コードは次のとおりです。
var getRangeObject = function(selectionObject) {
if (selectionObject.getRangeAt)
returnselectionObject.getRangeAt(0);
else { // 古いバージョンの Safari!
var range = document.createRange();
range.setStart(selectionObject.anchorNode,selectionObject.anchorOffset); ,selectionObject.focusOffset);
戻り値
}
}
var rangeObject = getRangeObject(userSelection);
理想的には、Selection オブジェクトの getRangeAt() メソッドを通じて W3C Range オブジェクトを取得できます。このメソッドは、指定されたインデックス値の範囲オブジェクトを返すことができます。通常、JavaScript の最初の Range のインデックス値は 0 です。

プログラムを使用して範囲を作成します

Safari 1.3 は getRangeAt() をサポートしていないため、このブラウザを考慮したい場合は、他のメソッドを使用して新しい Range を作成する必要があります物体。

var range = document.createRange();
上記のコード行は、コンテンツを挿入するために、setStart() と setEnd を渡す必要があります。 () メソッドは開始点と終了点を定義します。

これら 2 つのメソッドには 2 つのパラメーターが必要です。
1. 範囲の開始および終了 DOM ノード
2. 範囲の開始および終了テキスト オフセット。オフセットは、テキスト ノード内の選択したテキストの最初と最後の文字の位置を指します。

setStart() の 2 つのパラメーター属性は startContainer と startOffset で、setEnd() の 2 つのパラメーター属性は endContainer と endOffset です。

次の例を考えてみましょう:

男性は、たとえ50歳であっても、26歳以上でまだ結婚していない女性には決して触れるべきではありません。彼女は離婚したり、死別したりする可能性がありますが、未婚であることはできません。 26歳を過ぎても結婚していない場合、この種の女性は通常、精神的に異常があるか、そうでなければ深刻な問題を抱えています。市場が間違いを犯すことはほとんどありません。たとえ間違っても宝を拾える確率は非常に低いです。


結婚市場の将来の変化は非常に興味深い問題であり、本土経済の将来の動向にも決定的な影響を与えるでしょう。産業の分布と経済全体の効率。




  1. なぜ正確な数字は 26 なのでしょうか?

ここでは、範囲は 2 番目の

ノードから始まり、最初の

  • ノードで終わります。 (通常、テキスト ノードの最初の文字のインデックスは 0 です。)

    ノードのテキスト オフセット値は 8 であり、

  • ノードのオフセット値は 5 であるため、


    var startP = [the p ノード];
    var endLi = [2 番目の li ノード]
    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 年になり、Shi Xiaolong はスキャンダルに巻き込まれ、Safari 5 がリリースされてしばらく経ちました。したがって、Safari の下位バージョンを考慮するためだけに Range を作成するプログラムを使用する場合は、まったく必要ないと思います。特にこの魔法の国では、最初に Safari を使用する人はほとんどおらず、Safari が長い間 getRangeAt() をサポートしており、Chrome ブラウザも同様です。

    ここをクリックできます: Safari での getRangeAt テストデモ

    デモ ページ内のテキストの任意の部分を選択し、テスト ボタンをクリックすると、新しいバージョンの Safari の下に表示されますブラウザ 以下の図のような結果が表示されます:


    したがって、現在の環境では、Selection オブジェクトを Range オブジェクトに変換したい場合は、次のコード (完全バージョン) を使用するだけです。 🎜>



    コードをコピーします

    コードは次のとおりです。
    var userSelection, if ( window.getSelection) { //最新のブラウザuserSelection = window.getSelection(); } else if (document.selection) {
    //IE ブラウザは Opera を考慮するため、後ろ
    userSelection = document .selection.createRange();
    }

    //範囲オブジェクト
    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):

    相关JavaScript代码如下:
    复制代码 代码如下:

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

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

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

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

    完整JavaScript代码如下:
    复制代码 代码如下:



    <script> <br>var cssApplier; <br>window.onload = function() { <br>rangy.init(); <br>cssApplier = rangy.createCssClassApplier("selectClass", true); <br>document.body.onmouseup = function() { <br>cssApplier.toggleSelection(); <br>}; <br>}; <br></script>

    如果您看到下面的文字,可能是由于在其他网站或是RSS中阅读本文,本文原地址:http://www.zhangxinxu.com/wordpress/?p=1591,本文作者:张鑫旭,来自张鑫旭-鑫空间-鑫生活,访问原出处更多优秀技术文章。
    八、实际的应用
    微博之插入话题

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

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

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

    欢迎输入内容,点击测试。大致会有类似下面的效果(截自Chrome):
    JS範囲のHTMLドキュメント/テキストコンテンツの選択、ライブラリとアプリケーションの紹介_JavaScriptスキル

    源代码有些高度,为了节约篇幅,这里就不展示出来了,您可以在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

    Original article, please indicate when reprinting it from Zhang Xinxu-Xin Space-Xin Life

    声明:
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。