こんにちは。
とあるWebシステムにて、pタグの内側に改行およびテキスト以外のHTMLタグが双方含まれているHTMLを改修することがありました。
その際に試した方法を備忘録代わりに記載したいと思います。
置換対象のHTML
pタグ内にテキスト以外の要素が含まれているHTMLの例として以下のものを考えてみます。
下記の「TEXT」の文字列を「テキスト」に置換することを想定してみます。
See the Pen pTag_sample1 by n4gi-dev (@N4gi-dev) on CodePen.
※今回の記事では上記のHTML構造は変えられないことを前提とします。
うまくいかなかった例
textContentの場合
HTMLで文字列を置換するときに真っ先に浮かぶ方法はtextContentで置換する方法だと思います。
しかし、textContentはノードの内側の文字列が取得対象でありHTMLは取得できないため、今回のケースでは改行が無視されてしまいます。
const item = document.querySelector('.text');
item.textContent = item.textContent.replace(/TEXT/g, "テキスト");
See the Pen pTag_sample1 by n4gi-dev (@N4gi-dev) on CodePen.
innerTextの場合
文字を取得するためのプロパティには他にもinnerTextが存在します。これは文字列がレンダリングされる外見を取得するプロパティのため文字列の改行にも対応しています。
ノードとその子孫の「レンダリングされている」テキスト内容を示します。
基本的に innerText はテキストがレンダリングされる外見を意識しますが、 textContent はそうではありません。
実際に先ほどのJSをinnerTextに書き換えてみると確かに改行は反映されています。
(Qiita上では反映されていないように見えますがCODEPENに遷移すると改行されています)
ですが、このままだとpタグの内側に含まれている<span>タグのスタイリングが反映されていません。
const item = document.querySelector('.text');
item.innerText = item.innerText.replace(/TEXT/g, "テキスト");
See the Pen pTag_bad-sample2 by n4gi-dev (@N4gi-dev) on CodePen.
一方で今回のように文字列自体がHTMLで囲われていないケースでは、nextSiblingなどを用いてノードウォーキングする方法も使えませんでした。
innerHTMLを使う方法
今回のようにHTMLの構造を維持しながら文字列だけ置換したいケースではinnerHTMLで文字列を含むHTML要素ごと取得して置換することで意図した実装ができました。
const item = document.querySelector('.text');
item.innerHTML = item.innerHTML.replace(/TEXT/g, "テキスト");
See the Pen pTag-good-example by n4gi-dev (@N4gi-dev) on CodePen.
※今回は「予めHTML構造が決められているシステム=外部からの入力値を反映しないHTML」のためinnerHTMLを採用しています。
外部からの入力値を反映させる必要がある場合はXSS対策を別途検討してください。
まとめ
pタグの内側に改行や別のHTMLタグが含まれている要素の文字列を変更したい場合は、innerHTMLを使ってHTML構造を保持したまま文字列を置換してみてください。
この記事がどなたかの助けになれば幸いです。