最近SpringBoot x Thymeleafを本格的に使うようになったのですが、先日UI部品の共通化で少し混乱したことがあったのでコトの顛末をまとめておきます。
先に結論
先に結論だけ書いておきます。
共通化したいパーツが1つのタグに収まっていればth:replace
、そうでなければth:include
を使う。
Thymeleafでは部品の共通化のために2つの方法が提供されています。th:replace
とth:include
です。これらは上記のルールに基づいて使い分けることができます。
本家サイトにもth:includeとth:replaceの違いという項目はあり、以下のように書かれているのですが、
th:include と th:replace の違いって何でしょうか? th:include はホストタグの中にフラグメントの中身をインクルードする一方で th:replace は実際にホストタグをフラグメントで置換します。
私には初見ではよくわかりませんでした。
そこで挙動を整理してみたところ、本家の解説の意味にもシンプルなルールにも気づけました。
では順番に挙動を見ていきましょう。
以下に登場するコードはgithubにあげてあります。
th:replaceの挙動
th:replace
は書かれたタグをth:fragmentが書かれたタグで置き換えます。
単純にタグを置換するので、th:replaceタグとth:fragmentタグが1:1対応している必要があります。
たとえばこのような場合、th:replace
を使うことができます。
<div th:replace="common::replace"></div>
<hr class="ui divider">
<div th:replace="common::replace"></div>
<div class="ui container">
<div class="ui buttons">
<button class="ui primary button">Save</button>
<div class="or"></div>
<button class="ui button">Cancel</button>
</div>
</div>
<hr class="ui divider">
<div class="ui container">
<div class="ui buttons">
<button class="ui primary button">Save</button>
<div class="or"></div>
<button class="ui button">Cancel</button>
</div>
</div>
<button>
の集合がグループ化されて一つのタグにまとめられているので、th:replace
でガツンと置換してしまえばキレイに意図したViewが構築できますね。
th:includeの挙動
th:include
は書かれたタグはそのままに、タグの内部を書き換えます。
th:replace
と違い、共通部品と1:1対応でなくとも置換が可能です。
<div class="ui three item menu" th:include="common::include"></div>
<hr class="ui divider">
<div class="ui vertical menu" th:include="common::include"></div>
<div class="ui three item menu">
<a class="active item" href="#">item 1</a>
<a class="item" href="#">item 2</a>
<a class="item" href="#">item 3</a>
</div>
<hr class="ui divider">
<div class="ui vertical menu">
<a class="active item" href="#">item 1</a>
<a class="item" href="#">item 2</a>
<a class="item" href="#">item 3</a>
</div>
th:include
を書いたタグのclass指定によって、縦並びと横並びが入れ替わっています。このような指定をしたい時はth:include
が有効だといえます。
まとめ: 作れない構成もあるので気をつけて
しかし、これでは共通化部品が一つのタグにまとまっていなくて、かつ親タグが共通部品以外の子要素を持っていたら書けません。
<div>
<p>共通化したい部品1</p>
<p>共通化したい部品2</p>
<p>共通化したい部品3</p>
<div>このページ固有の要素たち</div>
</div>
一旦今はそのような状況に遭遇はしていませんが、そうなったらHTMLの構成で吸収するしかなさそうです。