web-dev-qa-db-ja.com

Javascriptで選択されたテキストの強調表示の確率

テキストコンテンツを含むhtmlページがあります。任意のテキストを選択してハイライトボタンを押すと、選択したテキストのスタイルを変更して同じものをハイライトできます。この機能を実装するために、私は次のメソッドを作成しました。

sel = window.getSelection();
var range = sel.getRangeAt(0);
var span = document.createElement('span');
span.className = "highlight" + color;
range.surroundContents(span);

これは、htmlタグのないテキストを選択した場合は正常に機能しますが、テキストの間にhtmlタグがあると、エラーが発生します。

「範囲」で「surroundContents」の実行に失敗しました:範囲が非テキストノードを部分的に選択しました。

この問題を解決する方法。パーツごとに同じものを個別に強調表示することは可能ですか(htmlタグで分割)?

20
dev_android

見る - Range.extractContents

document.getElementById('execute').addEventListener('click', function() {
    var range = window.getSelection().getRangeAt(0),
        span = document.createElement('span');

    span.className = 'highlight';
    span.appendChild(range.extractContents());
    range.insertNode(span);
});
.highlight { background-color: yellow; }
<div id="test">
    Select any part of <b>this text and</b> then click 'Run'.
</div>

<button id="execute">Run</button>
26
André Dion

この解決策は少し注意が必要ですが、それで十分だと思います

呼び出しによって取得した選択オブジェクトがよく見える場合

window.getSelection().getRangeAt(0)

startContainerstartOffsetendContainerendOffsetの4つのプロパティがあることがわかります。

したがって、startContainerからstartOffsetで開始し、そこから必要なスパンノードの配置を開始する必要があります。

endContainerが別のノードである場合は、startContainerからendContainerへのノードのトラバースを開始する必要があります。

トラバースするには、DOMオブジェクトから取得できる子ノードと兄弟ノードを確認する必要があります。したがって、最初にstartContainerを調べ、そのすべての子を調べて、子ノードがインライン要素であるかどうかを確認してから、その周りにスパンタグを適用します。次に、さまざまなコーナーケースのコーディングをいくつか記述する必要があります。

2
Parag Bhayani

これを試して:

newNode.appendChild(range.extractContents())

[〜#〜] mdn [〜#〜] によると:

部分的に選択されたノードは、ドキュメントフラグメントを有効にするために必要な親タグを含むように複製されます。

一方 Range.surroundContents

ただし、範囲が非テキストノードをその境界点の1つだけで分割する場合は、例外がスローされます。つまり、上記の代替方法とは異なり、部分的に選択されたノードがある場合、それらは複製されず、代わりに操作が失敗します。

テストしませんでしたが...

2
n00dl3