テキストコンテンツを含む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タグで分割)?
見る - 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>
この解決策は少し注意が必要ですが、それで十分だと思います
呼び出しによって取得した選択オブジェクトがよく見える場合
window.getSelection().getRangeAt(0)
startContainer
、startOffset
、endContainer
、endOffset
の4つのプロパティがあることがわかります。
したがって、startContainer
からstartOffset
で開始し、そこから必要なスパンノードの配置を開始する必要があります。
endContainer
が別のノードである場合は、startContainer
からendContainer
へのノードのトラバースを開始する必要があります。
トラバースするには、DOMオブジェクトから取得できる子ノードと兄弟ノードを確認する必要があります。したがって、最初にstartContainer
を調べ、そのすべての子を調べて、子ノードがインライン要素であるかどうかを確認してから、その周りにスパンタグを適用します。次に、さまざまなコーナーケースのコーディングをいくつか記述する必要があります。
これを試して:
newNode.appendChild(range.extractContents())
[〜#〜] mdn [〜#〜] によると:
部分的に選択されたノードは、ドキュメントフラグメントを有効にするために必要な親タグを含むように複製されます。
ただし、範囲が非テキストノードをその境界点の1つだけで分割する場合は、例外がスローされます。つまり、上記の代替方法とは異なり、部分的に選択されたノードがある場合、それらは複製されず、代わりに操作が失敗します。
テストしませんでしたが...