「画面にHTMLタグを含む文字列を描画する際に、HTMLタグはHTMLとして出力する」みたいなことをするために色々調べたので、いくつか覚えておきたいことを書き付けとく。

事前知識として

Vue.js公式サイトのテンプレート構文 > 展開という項目で紹介されている通り、Vue.jsにおいてテキスト展開は変数を二重中括弧(``)で囲うことで実現できる。

<!-- colorには"Red"という文字列が格納されているとする -->
<!-- 画面には「Red」という文字列が出力される。 -->
<p></p>

また、この記法はもっとも基本的なデータバインディングの形でもあり、colorプロパティの値が変更される度に出力内容が更新される。

ここまでが事前知識で、今回はこのcolorプロパティにHTMLタグを含んだ文字列を格納し、先にあげた「画面にHTMLタグを含む文字列を描画する際に、HTMLタグはHTMLとして出力する」を実現していく。

失敗談

まず初めは、単純にcolorにHTMLタグを含んだ文字列を格納し、それを二重中括弧記法で出力する。

<!-- colorには"Red<br />Blue"という文字列が格納されているとする -->
<p></p>

ここで期待する結果は文字列に含まれる<br />タグがHTMLタグとして出力されることで、それは下記のようになること。

<期待する結果>
Red
Blue

だが、これの結果は次のようになる。

<実行の結果>
Red<br />Blue

解決方法とその理由について

上記の実行結果は見ての通り、<br />タグがプレーンテキストとして出力されてしまっている。

これについては、再びVue.js公式サイトのテンプレート構文 > 生のHTMLに解決策と理由が記載されていた。

2重中括弧の mustaches は、データを HTML ではなく、プレーンなテキストとして扱います。実際の HTML として出力するためには、v-html ディレクティブを使用する必要があります

どうやら、二重中括弧記法ではプロパティの値をプレーンテキストとして出力するようになっていて、今回のようにHTMLとして出力したい場合はv-htmlディレクティブを使う必要があるとのこと。

なので、今回は次のようにしてあげればHTMLとして出力できた。

<!-- colorには"Red<br />Blue"という文字列が格納されているとする -->
<p v-html="color"></p>
<実行の結果>
Red
Blue

それで、なんで二重中括弧記法でのHTML出力を許可していないかについては次のように記載されていた。

XSS 脆弱性を容易に引き起こすので、ウェブサイトで動的に任意のHTMLを描画することは、非常に危険です。信頼できるコンテンツにだけ HTML 展開を利用してください。ユーザーから提供されたコンテンツに対しては決して使用してはいけません。

「言われてみれば確かに。。。」ってなる内容なんだけど、熱が入りすぎて視野が狭まってた。 今回はその自戒も含めて記事として残せたかなという感じ。

v-htmlでもfiltersを噛ませたい(おまけ)

二重中括弧記法でプロパティを出力する際に、filtersを使うことでデータを加工することができる。 二重中括弧記法でのfiltersの使い方は次のようになる。下記は配列の要素を" and "を挟んで結合し出力している。

// arrには["Red", "Blue"]という配列が格納されているとする


~省略~

filters: {
  join: function (value) {
    return value.join(" and ")
  }
}
<実行の結果>
Red and Blue

次に、この" and "ではなく<br />タグを挟んで結合したくなったとする。 この場合は二重中括弧記法でプロパティの展開を行うとHTMLタグがプレーンテキストとして、出力されてしまうのでv-htmlディレクティブを使う。 そこで気になるのがv-htmlにおけるfiltersの指定方法で、それに関してはこの記事が参考になった。

<!-- colorには"Red<br />Blue"という文字列が格納されているとする -->
<p v-html="$options.filters.json(color)"></p>
filters: {
  join: function (value) {
    return value.join("<br />")
  }
}
<実行の結果>
Red
Blue

これでv-htmlでもfiltersを指定することができた。以上。