プログラムでcontenteditable HTML要素のテキストを選択しますか?


119

JavaScriptでは、inputor textarea要素内のテキストをプログラムで選択できます。で入力をフォーカスしipt.focus()、でその内容を選択できますipt.select()。で特定の範囲を選択することもできますipt.setSelectionRange(from,to)

私の質問は、contenteditable要素でこれを行う方法はありますか?

elem.focus()キャレットをcontenteditable要素に配置するために、私はできることがわかりましたが、その後実行elem.select()しても機能しません(そして機能しませんsetSelectionRange)。それについてウェブ上で何も見つけることができませんが、おそらく私は間違ったことを探しています...

ちなみに、違いがある場合は、Google Chromeでのみ機能します。これはChrome拡張機能のためです。

回答:


170

Chromeで要素のコンテンツ(コンテンツ編集可能かどうかにかかわらず)をすべて選択する場合は、次のようにします。これは、Firefox、Safari 3以降、Opera 9以降(おそらく以前のバージョンも)、IE 9でも機能します。キャラクターレベルまで選択範囲を作成することもできます。必要なAPIは、DOM Range(現在の仕様はDOM Level 2でMDNも参照)と、新しいRange仕様MDN docs)の一部として指定されているSelection です。

function selectElementContents(el) {
    var range = document.createRange();
    range.selectNodeContents(el);
    var sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);
}

var el = document.getElementById("foo");
selectElementContents(el);

15
互換性を高めるにselectElementContents()は、setTimeout()またはrequestAnimationFrame()から呼び出す必要がありますonfocusjsfiddle.net/rudiedirkx/MgASG/1/showを
Rudie

@ディラン:よくわかりません。質問では、OPがすでに使用していると述べていfocus()ます。
Tim Down

4
@Rudie 互換性はどのアプリケーションにありますか?
yckart

デスクトップでうまく動作します。モバイルブラウザでは機能しません。選択されていません。iPhone iOS 11でSafariとChromeを試しました
キャンベル

1
@campbell:Safariでは少なくともiOSで機能しますが、すでに選択している必要があります。それ以外の場合、いいえ、おそらくユーザーエクスペリエンスの理由から、ブラウザーはJavaScriptに選択を表示することを許可しません。
Tim Down

34

Tim Downsの回答に加えて、oldIEでも機能するソリューションを作成しました。

var selectText = function() {
  var range, selection;
  if (document.body.createTextRange) {
    range = document.body.createTextRange();
    range.moveToElementText(this);
    range.select();
  } else if (window.getSelection) {
    selection = window.getSelection();
    range = document.createRange();
    range.selectNodeContents(this);
    selection.removeAllRanges();
    selection.addRange(range);
  }
};

document.getElementById('foo').ondblclick = selectText;​

IE 8以降、Firefox 3以降、Opera 9以降、Chrome 2以降でテスト済み。私もそれをjQueryプラグインに設定しました:

jQuery.fn.selectText = function() {
  var range, selection;
  return this.each(function() {
    if (document.body.createTextRange) {
      range = document.body.createTextRange();
      range.moveToElementText(this);
      range.select();
    } else if (window.getSelection) {
      selection = window.getSelection();
      range = document.createRange();
      range.selectNodeContents(this);
      selection.removeAllRanges();
      selection.addRange(range);
    }
  });
};

$('#foo').on('dblclick', function() {
  $(this).selectText();
});

...そして誰が興味を持っているか、ここにすべてのコーヒー中毒者のために同じです:

jQuery.fn.selectText = ->
  @each ->
    if document.body.createTextRange
      range = document.body.createTextRange()
      range.moveToElementText @
      range.select()
    else if window.getSelection
      selection = window.getSelection()
      range = document.createRange()
      range.selectNodeContents @
      selection.removeAllRanges()
      selection.addRange range
    return

更新:

ページ全体または編集可能領域のコンテンツを選択する場合( contentEditable)の切り替えてdesignModeを使用することで、より簡単に行うことができますdocument.execCommand

MDN小さなドキュメントの良い出発点があります。

var selectText = function () {
  document.execCommand('selectAll', false, null);
};

(IE6以降、Opera 9以降、Firefoy 3以降、Chrome 2以降で適切に動作します)http://caniuse.com/#search=execCommand


10

既存の回答はすべてdiv要素を扱っているので、spans を使用してそれを行う方法を説明します。

でテキスト範囲を選択する場合、微妙な違いがありますspan。テキストの開始インデックスと終了インデックスを渡すことができるようにするには、ここでText説明するようにノードを使用する必要があります

startNodeがタイプText、Comment、またはCDATASectionのノードである場合、startOffsetはstartNodeの先頭からの文字数です。他のノードタイプの場合、startOffsetは、startNodeの開始間の子ノードの数です。

var e = document.getElementById("id of the span element you want to select text in");
var textNode = e.childNodes[0]; //text node is the first child node of a span

var r = document.createRange();
var startIndex = 0;
var endIndex = textNode.textContent.length;
r.setStart(textNode, startIndex);
r.setEnd(textNode, endIndex);

var s = window.getSelection();
s.removeAllRanges();
s.addRange(r);

本当にそうでなければなりません: r.setStart(e.firstChild,0); r.setEnd(e.lastChild,e.lastChild.textContent.length); もちろん、e.firstChildが実際にnullでないことを確認する必要があります。
Yorick

2
<div><span>要素での選択には違いはありません。少なくとも、あなたが説明したとおりではありません。
Tim Down

divとspanの間には違いがあり、divのソリューションがspanで正しく機能しない場合があります。たとえば、divソリューションを使用してプログラムでテキストを選択し、新しいコンテンツを貼り付けると、テキスト全体ではなく一部のみが置き換えられ、chromeとfirefoxの間に違いがあります
neosonne

6

Rangyでは、同じコードでこのクロスブラウザーを実行できます。Rangyは、選択用のDOMメソッドのクロスブラウザー実装です。これは十分にテストされており、これにより苦痛が大幅に軽減されます。私はそれなしでcontenteditableに触れることを拒否します。

あなたはここでランジーを見つけることができます:

http://code.google.com/p/rangy/

プロジェクトが乱暴であるため、ブラウザーがIE 8以前であり、選択用にまったく異なるネイティブAPIがある場合でも、いつでもこれを作成できます。

var range = rangy.createRange();
range.selectNodeContents(contentEditableNode);
var sel = rangy.getSelection();
sel.removeAllRanges();
sel.addRange(range);

ここで、「contentEditableNode」は、contenteditable属性を持つDOMノードです。あなたはこのようにそれをフェッチするかもしれません:

var contentEditable = document.getElementById('my-editable-thing');

または、jQueryがすでにプロジェクトの一部であり、それが便利である場合:

var contentEditable = $('.some-selector')[0];

RangyプロジェクトはGithubに移動しました:github.com/timdown/rangy
tanius

4

現代の物事のやり方はこうです。MDNの詳細

document.addEventListener('dblclick', (event) => {
  window.getSelection().selectAllChildren(event.target)
})
<div contenteditable="true">Some text</div>


よろしくお願いします。Fwiw、そのMDNページはこのテクノロジーを実験的とマークしています。ただし、2020
動作します。– JohnK

2

[間違いを修正するために更新]

これは、Chromeで適切に動作するように見えるこの回答から適応された例です-contenteditable divで範囲を選択します

var elm = document.getElementById("myText"),
    fc = elm.firstChild,
    ec = elm.lastChild,
    range = document.createRange(),
    sel;
elm.focus();
range.setStart(fc,1);
range.setEnd(ec,3);
sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);

HTMLは次のとおりです。

<div id="myText" contenteditable>test</div>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.