2022年10月30日

選択と Range

この章では、ドキュメント内の選択と、<input> などのフォームフィールドでの選択について説明します。

JavaScript は、既存の選択範囲にアクセスしたり、DOM ノード全体または一部を選択/選択解除したり、選択したコンテンツをドキュメントから削除したり、タグで囲んだりすることができます。

一般的なタスクのレシピは、章の最後にある「まとめ」セクションにあります。おそらくそれで現在のニーズは満たされるでしょうが、全文を読めばもっと多くのことが得られます。

基礎となる Range オブジェクトと Selection オブジェクトは理解しやすく、それらを理解すれば、レシピがなくても思い通りに操作できます。

Range

選択の基本概念は Range で、これは本質的に「境界点」のペア、つまり Range の開始点と終了点です。

Range オブジェクトはパラメータなしで作成されます

let range = new Range();

その後、range.setStart(node, offset)range.setEnd(node, offset) を使用して選択範囲を設定できます。

ご想像のとおり、さらに Range オブジェクトを選択に使用しますが、まずはそのようなオブジェクトをいくつか作成してみましょう。

テキストの部分的な選択

興味深いのは、両方のメソッドの最初の引数 node がテキストノードまたは要素ノードのいずれかであり、2 番目の引数の意味がそれに依存することです。

node がテキストノードの場合、offset はそのテキスト内の位置でなければなりません。

たとえば、要素 <p>Hello</p> が与えられた場合、文字「ll」を含む Range を次のように作成できます

<p id="p">Hello</p>
<script>
  let range = new Range();
  range.setStart(p.firstChild, 2);
  range.setEnd(p.firstChild, 4);

  // toString of a range returns its content as text
  console.log(range); // ll
</script>

ここでは、<p> の最初の子(つまりテキストノード)を取得し、その中のテキストの位置を指定します

要素ノードの選択

または、node が要素ノードの場合、offset は子の番号でなければなりません。

これは、テキストの途中で停止するのではなく、ノード全体を含む Range を作成するのに便利です。

たとえば、より複雑なドキュメントフラグメントがあるとします

<p id="p">Example: <i>italic</i> and <b>bold</b></p>

要素ノードとテキストノードの両方を含む DOM 構造は次のとおりです

"Example: <i>italic</i>" の Range を作成してみましょう。

見てのとおり、この句は <p> のちょうど 2 つの子で構成されており、インデックスは 01 です

  • 開始点は、親 node として <p> を、オフセットとして 0 を持ちます。

    そのため、range.setStart(p, 0) として設定できます。

  • 終了点も親 node として <p> を持ちますが、オフセットは 2 です(offset までを含まない範囲を指定します)。

    そのため、range.setEnd(p, 2) として設定できます。

これがデモです。実行すると、テキストが選択されていることがわかります

<p id="p">Example: <i>italic</i> and <b>bold</b></p>

<script>
  let range = new Range();

  range.setStart(p, 0);
  range.setEnd(p, 2);

  // toString of a range returns its content as text, without tags
  console.log(range); // Example: italic

  // apply this range for document selection (explained later below)
  document.getSelection().addRange(range);
</script>

これは、Range の開始/終了番号を設定し、他のバリアントを探索できる、より柔軟なテストスタンドです

<p id="p">Example: <i>italic</i> and <b>bold</b></p>

From <input id="start" type="number" value=1> – To <input id="end" type="number" value=4>
<button id="button">Click to select</button>
<script>
  button.onclick = () => {
    let range = new Range();

    range.setStart(p, start.value);
    range.setEnd(p, end.value);

    // apply the selection, explained later below
    document.getSelection().removeAllRanges();
    document.getSelection().addRange(range);
  };
</script>

たとえば、同じ <p> 内でオフセット 1 から 4 までを選択すると、<i>italic</i> and <b>bold</b> という Range が得られます

開始ノードと終了ノードは異なる場合があります

setStartsetEnd で同じノードを使用する必要はありません。Range は、多くの無関係なノードにまたがることができます。ドキュメント内で終了が開始の後にあることだけが重要です。

より大きなフラグメントの選択

例では、次のようにより大きな選択範囲を作成してみましょう

その方法はすでにわかっています。開始と終了をテキストノードの相対オフセットとして設定するだけです。

作成する必要がある Range は、

  • <p> の最初の子の 2 番目の位置から開始します("Example: " の最初の 2 文字を除くすべてを取得します)
  • <b> の最初の子の 3 番目の位置で終了します("bold" の最初の 3 文字を取得しますが、それ以上は取得しません)
<p id="p">Example: <i>italic</i> and <b>bold</b></p>

<script>
  let range = new Range();

  range.setStart(p.firstChild, 2);
  range.setEnd(p.querySelector('b').firstChild, 3);

  console.log(range); // ample: italic and bol

  // use this range for selection (explained later)
  window.getSelection().addRange(range);
</script>

見てのとおり、必要な範囲の Range を作成するのは非常に簡単です。

ノード全体を取得したい場合は、setStart/setEnd に要素を渡すことができます。そうでない場合は、テキストレベルで作業できます。

Range プロパティ

上記の例で作成した Range オブジェクトには、次のプロパティがあります

  • startContainerstartOffset – 開始のノードとオフセット、
    • 上記の例では:<p> 内の最初のテキストノードと 2 です。
  • endContainerendOffset – 終了のノードとオフセット、
    • 上記の例では:<b> 内の最初のテキストノードと 3 です。
  • collapsed – ブール値。Range の開始と終了が同じ点にある場合(つまり、Range 内にコンテンツがない場合)は true です。
    • 上記の例では:false
  • commonAncestorContainer – Range 内のすべてのノードの最も近い共通の祖先、
    • 上記の例では:<p>

Range 選択メソッド

Range を操作するための便利なメソッドが多数あります。

setStartsetEnd はすでに見てきました。他にも同様のメソッドがあります。

Range の開始の設定

  • setStart(node, offset) 開始を次の場所に設定します:node 内の offset の位置
  • setStartBefore(node) 開始を次の場所に設定します:node の直前
  • setStartAfter(node) 開始を次の場所に設定します:node の直後

Range の終了の設定(同様のメソッド)

  • setEnd(node, offset) 終了を次の場所に設定します:node 内の offset の位置
  • setEndBefore(node) 終了を次の場所に設定します:node の直前
  • setEndAfter(node) 終了を次の場所に設定します:node の直後

技術的には、setStart/setEnd は何でもできますが、より多くのメソッドはより多くの利便性を提供します。

これらのすべてのメソッドで、node はテキストノードまたは要素ノードのいずれかになります。テキストノードの場合、offset はその文字数をスキップしますが、要素ノードの場合はその子ノード数をスキップします。

Range を作成するためのさらに多くのメソッド

  • selectNode(node) node 全体を選択するように Range を設定します
  • selectNodeContents(node) node のコンテンツ全体を選択するように Range を設定します
  • collapse(toStart) toStart=true の場合は end=start を設定し、そうでない場合は start=end を設定して、Range を折りたたみます
  • cloneRange() 同じ開始/終了を持つ新しい Range を作成します

Range 編集メソッド

Range が作成されると、次のメソッドを使用してそのコンテンツを操作できます

  • deleteContents() – ドキュメントから Range のコンテンツを削除します
  • extractContents() – ドキュメントから Range のコンテンツを削除し、DocumentFragment として返します
  • cloneContents() – Range のコンテンツを複製し、DocumentFragment として返します
  • insertNode(node) – Range の先頭に node をドキュメントに挿入します
  • surroundContents(node) – Range のコンテンツを node で囲みます。これが機能するためには、Range にその中のすべての要素の開始タグと終了タグの両方が含まれている必要があります。<i>abc のような部分的な Range は使用できません。

これらのメソッドを使用すると、基本的に選択したノードに対して何でもできます。

これが、それらを実際に確認するためのテストスタンドです

Click buttons to run methods on the selection, "resetExample" to reset it.

<p id="p">Example: <i>italic</i> and <b>bold</b></p>

<p id="result"></p>
<script>
  let range = new Range();

  // Each demonstrated method is represented here:
  let methods = {
    deleteContents() {
      range.deleteContents()
    },
    extractContents() {
      let content = range.extractContents();
      result.innerHTML = "";
      result.append("extracted: ", content);
    },
    cloneContents() {
      let content = range.cloneContents();
      result.innerHTML = "";
      result.append("cloned: ", content);
    },
    insertNode() {
      let newNode = document.createElement('u');
      newNode.innerHTML = "NEW NODE";
      range.insertNode(newNode);
    },
    surroundContents() {
      let newNode = document.createElement('u');
      try {
        range.surroundContents(newNode);
      } catch(e) { console.log(e) }
    },
    resetExample() {
      p.innerHTML = `Example: <i>italic</i> and <b>bold</b>`;
      result.innerHTML = "";

      range.setStart(p.firstChild, 2);
      range.setEnd(p.querySelector('b').firstChild, 3);

      window.getSelection().removeAllRanges();
      window.getSelection().addRange(range);
    }
  };

  for(let method in methods) {
    document.write(`<div><button onclick="methods.${method}()">${method}</button></div>`);
  }

  methods.resetExample();
</script>

Range を比較するためのメソッドも存在しますが、これらはめったに使用されません。必要な場合は、仕様書 または MDN マニュアル を参照してください。

Selection

Range は、選択範囲を管理するための汎用オブジェクトです。ただし、Range を作成しても、画面に選択範囲が表示されるわけではありません。

Range オブジェクトを作成して渡すことができますが、それだけでは視覚的に何も選択されません。

ドキュメントの選択範囲は Selection オブジェクトで表され、window.getSelection() または document.getSelection() として取得できます。選択範囲には、ゼロ個以上の Range が含まれる場合があります。少なくとも、Selection API 仕様 ではそのように述べられています。ただし実際には、Firefox のみ Ctrl+クリック (Mac の場合は Cmd+クリック) を使用してドキュメント内の複数の Range を選択できます。

これは、Firefox で作成された 3 つの Range を持つ選択範囲のスクリーンショットです

他のブラウザは最大 1 つの Range をサポートしています。後述するように、一部の Selection メソッドは複数の Range があることを暗示していますが、繰り返しますが、Firefox を除くすべてのブラウザでは最大 1 つです。

これは、現在の選択範囲(何かを選択してクリック)をテキストとして表示する小さなデモです

Selection プロパティ

前述のとおり、選択範囲には理論的には複数の Range が含まれる場合があります。これらの Range オブジェクトは、次のメソッドを使用して取得できます

  • getRangeAt(i)0 から始まる i 番目の Range を取得します。Firefox を除くすべてのブラウザでは、0 のみを使用します。

また、より便利なプロパティも存在します。

Range と同様に、選択オブジェクトには「アンカー」と呼ばれる開始と「フォーカス」と呼ばれる終了があります。

主な Selection プロパティは次のとおりです

  • anchorNode – 選択範囲が開始されるノード、
  • anchorOffset – 選択範囲が開始される anchorNode 内のオフセット、
  • focusNode – 選択範囲が終了するノード、
  • focusOffset – 選択範囲が終了する focusNode 内のオフセット、
  • isCollapsed – 選択範囲が何も選択していない(空の Range)場合、または存在しない場合は true です。
  • rangeCount – 選択範囲内の Range の数。Firefox を除くすべてのブラウザでは最大 1 です。
Selection の終了/開始と Range の比較

選択範囲のアンカー/フォーカスと Range の開始/終了には重要な違いがあります。

ご存知のとおり、Range オブジェクトは常に開始が終了の前にあります。

選択範囲の場合、必ずしもそうとは限りません。

マウスで何かを選択すると、「左から右」または「右から左」のどちらの方向でも実行できます。

言い換えれば、マウスボタンが押されて、ドキュメント内で前方に移動すると、その終了(フォーカス)は開始(アンカー)の後になります。

たとえば、ユーザーがマウスで選択を開始し、「Example」から「italic」に移動した場合

…しかし、同じ選択を逆方向に実行することもできます。「italic」から「Example」に開始する(逆方向)と、その終了(フォーカス)は開始(アンカー)の前にあります

Selection イベント

選択範囲を追跡するためのイベントがあります

  • elem.onselectstart – 要素 elem 上(またはその内部)で specifically 選択が*開始*されたとき。たとえば、ユーザーがマウスボタンを押してポインタを動かし始めたときです。
    • デフォルトアクションを防止すると、選択の開始がキャンセルされます。そのため、この要素から選択を開始することは不可能になりますが、要素は選択可能なままです。訪問者は、他の場所から選択を開始する必要があります。
  • document.onselectionchange – 選択が変更または開始されるたびに発生します。
    • 注意: このハンドラーはdocumentにのみ設定でき、ドキュメント内のすべての選択を追跡します。

選択追跡デモ

小さなデモをご紹介します。document上の現在の選択範囲を追跡し、その境界を表示します。

<p id="p">Select me: <i>italic</i> and <b>bold</b></p>

From <input id="from" disabled> – To <input id="to" disabled>
<script>
  document.onselectionchange = function() {
    let selection = document.getSelection();

    let {anchorNode, anchorOffset, focusNode, focusOffset} = selection;

    // anchorNode and focusNode are text nodes usually
    from.value = `${anchorNode?.data}, offset ${anchorOffset}`;
    to.value = `${focusNode?.data}, offset ${focusOffset}`;
  };
</script>

選択コピーのデモ

選択したコンテンツをコピーするには、2つのアプローチがあります。

  1. document.getSelection().toString()を使用して、テキストとして取得できます。
  2. または、フォーマットを維持する必要がある場合など、DOM全体をコピーするには、getRangeAt(...)で基礎となる範囲を取得できます。Rangeオブジェクトには、コンテンツを複製してDocumentFragmentオブジェクトとして返すcloneContents()メソッドがあり、それを他の場所に挿入できます。

選択したコンテンツをテキストとDOMノードの両方としてコピーするデモを次に示します。

<p id="p">Select me: <i>italic</i> and <b>bold</b></p>

Cloned: <span id="cloned"></span>
<br>
As text: <span id="astext"></span>

<script>
  document.onselectionchange = function() {
    let selection = document.getSelection();

    cloned.innerHTML = astext.innerHTML = "";

    // Clone DOM nodes from ranges (we support multiselect here)
    for (let i = 0; i < selection.rangeCount; i++) {
      cloned.append(selection.getRangeAt(i).cloneContents());
    }

    // Get as text
    astext.innerHTML += selection;
  };
</script>

選択メソッド

範囲を追加/削除することで、選択範囲を操作できます。

  • getRangeAt(i)0 から始まる i 番目の Range を取得します。Firefox を除くすべてのブラウザでは、0 のみを使用します。
  • addRange(range) – 選択範囲にrangeを追加します。Firefox以外のすべてのブラウザは、選択範囲に既に関連付けられた範囲がある場合、呼び出しを無視します。
  • removeRange(range) – 選択範囲からrangeを削除します。
  • removeAllRanges() – すべての範囲を削除します。
  • empty()removeAllRangesのエイリアスです。

中間Range呼び出しなしで、選択範囲を直接操作するための便利なメソッドもあります。

  • collapse(node, offset) – 選択範囲を、指定されたnodeoffset位置で開始および終了する新しい範囲に置き換えます。
  • setPosition(node, offset)collapseのエイリアスです。
  • collapseToStart() – 選択の開始位置に縮小(空の範囲に置き換え)します。
  • collapseToEnd() – 選択の終了位置に縮小します。
  • extend(node, offset) – 選択範囲のフォーカスを、指定されたnodeoffset位置に移動します。
  • setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset) – 選択範囲を開始anchorNode/anchorOffsetと終了focusNode/focusOffsetで指定された範囲に置き換えます。それらの間のすべてのコンテンツが選択されます。
  • selectAllChildren(node)nodeのすべての子を選択します。
  • deleteFromDocument() – 選択したコンテンツをドキュメントから削除します。
  • containsNode(node, allowPartialContainment = false) – 選択範囲にnodeが含まれているかどうかを確認します(2番目の引数がtrueの場合、部分的に含まれている場合も含まれます)。

ほとんどのタスクでは、これらのメソッドで十分であり、基礎となるRangeオブジェクトにアクセスする必要はありません。

たとえば、段落<p>の内容全体を選択するには、次のようにします。

<p id="p">Select me: <i>italic</i> and <b>bold</b></p>

<script>
  // select from 0th child of <p> to the last child
  document.getSelection().setBaseAndExtent(p, 0, p, p.childNodes.length);
</script>

範囲を使用して同じことを行うには、次のようにします。

<p id="p">Select me: <i>italic</i> and <b>bold</b></p>

<script>
  let range = new Range();
  range.selectNodeContents(p); // or selectNode(p) to select the <p> tag too

  document.getSelection().removeAllRanges(); // clear existing selection if any
  document.getSelection().addRange(range);
</script>
何かを選択するには、最初に既存の選択を削除します。

ドキュメントの選択範囲が既に存在する場合は、最初にremoveAllRanges()で空にします。その後、範囲を追加します。そうでない場合、Firefox以外のすべてのブラウザは新しい範囲を無視します。

例外は、setBaseAndExtentなど、既存の選択範囲を置き換える一部の選択メソッドです。

フォームコントロールでの選択

inputtextareaなどのフォーム要素は、SelectionオブジェクトやRangeオブジェクトを使用せずに、選択のための特別なAPIを提供します。入力値はHTMLではなくプレーンテキストであるため、そのようなオブジェクトは必要なく、すべてがはるかに単純です。

プロパティ

  • input.selectionStart – 選択開始位置(書き込み可能)、
  • input.selectionEnd – 選択終了位置(書き込み可能)、
  • input.selectionDirection – 選択方向。"forward"、"backward"、または"none"(たとえば、マウスをダブルクリックして選択した場合)のいずれかです。

イベント

  • input.onselect – 何かが選択されたときにトリガーされます。

メソッド

  • input.select() – テキストコントロール(inputの代わりにtextareaも可)内のすべてを選択します。

  • input.setSelectionRange(start, end, [direction]) – 選択範囲を、指定された方向(オプション)で、位置startからendまでに変更します。

  • input.setRangeText(replacement, [start], [end], [selectionMode]) – テキストの範囲を新しいテキストに置き換えます。

    オプションの引数startendを指定した場合、範囲の開始と終了が設定されます。そうでない場合は、ユーザーの選択範囲が使用されます。

    最後の引数selectionModeは、テキストが置き換えられた後に選択範囲をどのように設定するかを決定します。可能な値は次のとおりです。

    • "select" – 新しく挿入されたテキストが選択されます。
    • "start" – 選択範囲は、挿入されたテキストの直前で折りたたまれます(カーソルは直前に配置されます)。
    • "end" – 選択範囲は、挿入されたテキストの直後で折りたたまれます(カーソルは直後に配置されます)。
    • "preserve" – 選択範囲を維持しようとします。これがデフォルトです。

では、これらのメソッドの動作を見てみましょう。

例:選択の追跡

たとえば、次のコードはonselectイベントを使用して選択を追跡します。

<textarea id="area" style="width:80%;height:60px">
Selecting in this text updates values below.
</textarea>
<br>
From <input id="from" disabled> – To <input id="to" disabled>

<script>
  area.onselect = function() {
    from.value = area.selectionStart;
    to.value = area.selectionEnd;
  };
</script>

注意

  • onselectは何かが選択されたときにトリガーされますが、選択が解除されたときにはトリガーされません。
  • 仕様によると、document.onselectionchangeイベントは、フォームコントロール内の選択に対してはトリガーされません。これは、documentの選択範囲や範囲に関連していないためです。一部のブラウザはそれを生成しますが、それに依存すべきではありません。

例: カーソルの移動

selectionStartselectionEnd を変更することで、選択範囲を設定できます。

重要なエッジケースは、selectionStartselectionEnd が等しい場合です。その場合、それはカーソル位置と正確に一致します。言い換えれば、何も選択されていない場合、選択範囲はカーソル位置で折りたたまれます。

そのため、selectionStartselectionEnd に同じ値を設定することで、カーソルを移動します。

例:

<textarea id="area" style="width:80%;height:60px">
Focus on me, the cursor will be at position 10.
</textarea>

<script>
  area.onfocus = () => {
    // zero delay setTimeout to run after browser "focus" action finishes
    setTimeout(() => {
      // we can set any selection
      // if start=end, the cursor is exactly at that place
      area.selectionStart = area.selectionEnd = 10;
    });
  };
</script>

例: 選択範囲の変更

選択範囲の内容を変更するには、`input.setRangeText()` メソッドを使用できます。もちろん、`selectionStart/End` を読み取り、選択範囲の情報に基づいて `value` の対応する部分文字列を変更することもできますが、`setRangeText` はより強力で、多くの場合より便利です。

これはやや複雑なメソッドです。最も単純な1つの引数の形式では、ユーザーが選択した範囲を置き換え、選択範囲を削除します。

たとえば、ここではユーザーの選択範囲が `*...*` で囲まれます。

<input id="input" style="width:200px" value="Select here and click the button">
<button id="button">Wrap selection in stars *...*</button>

<script>
button.onclick = () => {
  if (input.selectionStart == input.selectionEnd) {
    return; // nothing is selected
  }

  let selected = input.value.slice(input.selectionStart, input.selectionEnd);
  input.setRangeText(`*${selected}*`);
};
</script>

より多くの引数を使用すると、範囲の `start` と `end` を設定できます。

この例では、入力テキストで `"THIS"` を探し、それを置き換え、置き換えられたテキストを選択したままにします。

<input id="input" style="width:200px" value="Replace THIS in text">
<button id="button">Replace THIS</button>

<script>
button.onclick = () => {
  let pos = input.value.indexOf("THIS");
  if (pos >= 0) {
    input.setRangeText("*THIS*", pos, pos + 4, "select");
    input.focus(); // focus to make selection visible
  }
};
</script>

例: カーソル位置への挿入

何も選択されていない場合、または `setRangeText` で等しい `start` と `end` を使用した場合、新しいテキストが挿入されるだけで、何も削除されません。

`setRangeText` を使用して、カーソル位置に何かを挿入することもできます。

ここでは、カーソル位置に `"HELLO"` を挿入し、カーソルをその直後に配置するボタンを示します。選択範囲が空でない場合は、選択範囲が置き換えられます(`selectionStart!=selectionEnd` を比較することで検出でき、代わりに別の処理を行うことができます)。

<input id="input" style="width:200px" value="Text Text Text Text Text">
<button id="button">Insert "HELLO" at cursor</button>

<script>
  button.onclick = () => {
    input.setRangeText("HELLO", input.selectionStart, input.selectionEnd, "end");
    input.focus();
  };
</script>

選択不可にする

何かを選択不可にするには、3つの方法があります。

  1. CSS プロパティ `user-select: none` を使用します。

    <style>
    #elem {
      user-select: none;
    }
    </style>
    <div>Selectable <div id="elem">Unselectable</div> Selectable</div>

    これにより、`elem` で選択を開始することはできません。ただし、ユーザーは他の場所で選択を開始し、`elem` を選択範囲に含めることができます。

    その場合、`elem` は `document.getSelection()` の一部になるため、実際には選択が行われますが、その内容は通常コピーペーストで無視されます。

  2. `onselectstart` または `mousedown` イベントでデフォルトアクションを防止します。

    <div>Selectable <div id="elem">Unselectable</div> Selectable</div>
    
    <script>
      elem.onselectstart = () => false;
    </script>

    これにより、`elem` での選択の開始は防止されますが、訪問者は別の要素で選択を開始し、`elem` に拡張することができます。

    これは、選択をトリガーする同じアクションに別のイベントハンドラーがある場合に便利です(例: `mousedown`)。そのため、選択を無効にして競合を回避しますが、`elem` の内容をコピーすることはできます。

  3. また、選択が発生した後に `document.getSelection().empty()` を使用して、選択を事後的にクリアすることもできます。これは、選択が表示されたり消えたりするため、不要な点滅が発生するため、めったに使用されません。

参考資料

まとめ

選択のための2つの異なる API について説明しました。

  1. ドキュメントの場合: `Selection` オブジェクトと `Range` オブジェクト。
  2. `input`、`textarea` の場合: 追加のメソッドとプロパティ。

2番目の API は、テキストを扱うため非常にシンプルです。

最もよく使用されるレシピはおそらく次のとおりです。

  1. 選択範囲の取得
    let selection = document.getSelection();
    
    let cloned = /* element to clone the selected nodes to */;
    
    // then apply Range methods to selection.getRangeAt(0)
    // or, like here, to all ranges to support multi-select
    for (let i = 0; i < selection.rangeCount; i++) {
      cloned.append(selection.getRangeAt(i).cloneContents());
    }
  2. 選択範囲の設定
    let selection = document.getSelection();
    
    // directly:
    selection.setBaseAndExtent(...from...to...);
    
    // or we can create a range and:
    selection.removeAllRanges();
    selection.addRange(range);

最後に、カーソルについてです。`<textarea>` のような編集可能な要素のカーソル位置は、常に選択範囲の開始または終了位置にあります。カーソル位置を取得したり、`elem.selectionStart` と `elem.selectionEnd` を設定することでカーソルを移動したりするために使用できます。

チュートリアルマップ

コメント

コメントする前にこれを読んでください…
  • 改善のための提案がある場合は、コメントする代わりに、GitHub の issue またはプルリクエストを送信してください。
  • 記事の内容が理解できない場合は、詳しく説明してください。
  • 数語のコードを挿入するには、`<code>` タグを使用し、複数行の場合は `<pre>` タグで囲み、10行を超える場合はサンドボックス(plnkrjsbincodepen…)を使用してください。