# 概述
在web开发中,我们经常会将公共头,公共尾,菜单等部分提取成模板供其它页面使用。在thymeleaf中,通过th:fragment、th:include、th:replace、参数化模板配置、css选择器加载代码块等实现。下文通过例子来说明用法:
fragment语法
~~~
通过 th:fragment 和 css选择器加载代码块
th:include 和 th:replace
参数化模板配置
~~~
这应该是Thymeleaf系列的最后一篇,不容易啊!夸夸一下自己,呵呵!
注意
` spring boot 1.5.4 默认使用的 thymeleaf 2,这里只演示thymeleaf 2语法`
## 定义模板
在Thymeleaf 中,我们可以使用th:fragment属性来定义一个模板。
我们可以新建一个简单的页尾模板,如:/resoures/templates/footer.html,内容如下:
~~~
<!DOCTYPE html SYSTEM "http://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-4.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="copyright">
© 2016 xxx
</div>
</body>
</html>
~~~
上面定义了一个叫做copyright的片段,接着我们可以使用th:include或者th:replace属性来使用它:
~~~
<body>
...
<div th:include="footer :: copyright"></div>
</body>
~~~
其中th:include中的参数格式为`templatename::[domselector]`,
其中templatename是模板名(如footer),domselector是可选的dom选择器。如果只写templatename,不写domselector,则会加载整个模板。
当然,这里我们也可以写表达式:
`<div th:include="footer :: (${user.isAdmin}? #{footer.admin} : #{footer.normaluser})"></div>`
模板片段可以被包含在任意`th:*`属性中,并且可以使用目标页面中的上下文变量。
不通过th:fragment引用模板
通过强大的dom选择器,我们可以在不添加任何Thymeleaf属性的情况下定义模板:
~~~
...
<div id="copy-section">
© xxxxxx
</div>
...
~~~
通过dom选择器来加载模板,如id为copy-section
~~~
<body>
...
<div th:include="footer :: #copy-section">
</div>
</body>
~~~
## 公共页
/templates/template/footer.html
此页面定义待加载的模板页面
```
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<meta charset="UTF-8" />
<body>
<!-- th:fragment 定义用于加载的块 -->
<span th:fragment="copy"> 2017 hry loaded by fragment=copy</span>
<span id="copy-section"> 2017 hry loaded by id=copy-section</span>
<!-- 定义模板时,可以传入参数 -->
<span th:fragment="frag(month, date) "> <span th:text="'welcome hry come in ' + ${month} + '-' + ${date}"></span></span>
</body>
</html>
```
## fragment语法
/templates/template/footer.html:定义要加载代码块copy
~~~
<!-- th:fragment 定义用于加载的块 -->
<span th:fragment="copy"> 2017 hry loaded by fragment=copy</span>
~~~
/templates/template/template.html:通过th:include在本页中加载以上的代码块copy,fragment加载语法如下:
```
templatename::selector:”::”前面是模板文件名,后面是选择器
::selector:只写选择器,这里指fragment名称,则加载本页面对应的fragment
templatename:只写模板文件名,则加载整个页面
================== fragment语法 ============================= <br />
<!-- 语法说明 "::"前面是模板文件名,后面是选择器 -->
<div th:include="template/footer::copy"></div>
<!-- 只写选择器,这里指fragment名称,则加载本页面对应的fragment -->
<div th:include="::#thispage"></div>
<!-- 只写模板文件名,则加载整个页面 -->
<div th:include="template/footer"></div>
================= 加载块 ============================
<br />
<span id="thispage">
div in this page.
</span>
```
运行结果输出:
```
================== fragment语法 ============================= <br />
<!-- 语法说明 "::"前面是模板文件名,后面是选择器 -->
<div> 2017 hry loaded by fragment=copy</div>
<!-- 只写选择器,这里指fragment名称,则加载本页面对应的fragment -->
<div>
div in this page.
</div>
<!-- 只写模板文件名,则加载整个页面 -->
<div>
<html>
<meta charset="UTF-8" />
<body>
<!-- th:fragment 定义用于加载的块 -->
<span> 2017 hry loaded by fragment=copy</span>
<span id="copy-section"> 2017 hry loaded by id=copy-section</span>
<!-- 定义模板时,可以传入参数 -->
<span> <span>welcome hry come in 6-19</span></span>
</body>
</html>
</div>
```
## 通过 th:fragment 和 css选择器加载代码块
/templates/template/footer.html:
除了th:fragment外,还可以css选择器加载代码块。下文定义th:fragment=”copy”和id=”copy-section”。
```
<!-- th:fragment 定义用于加载的块 -->
<span th:fragment="copy"> 2017 hry loaded by fragment=copy</span>
<span id="copy-section"> 2017 hry loaded by id=copy-section</span>
```
/templates/template/template.html:
通过 th:fragment 加载代码块
通过css选择器加载代码块
```
================= 通过 th:fragment 和 css选择器加载代码块 =================
<!-- 这里加载”th:fragment 定义用于加载的块“ -->
<div th:include="template/footer::copy"></div>
<!-- 这里加载”id=copy-section“的节点 -->
<div th:include="template/footer::#copy-section"></div>
```
运行结果输出:
```
================= 通过 th:fragment 和 css选择器加载代码块 =================
<!-- 这里加载”th:fragment 定义用于加载的块“ -->
<div> 2017 hry loaded by fragment=copy</div>
<!-- 这里加载”id=copy-section“的节点 -->
<div> 2017 hry loaded by id=copy-section</div>
```
## th:include 和 th:replace
th:include 和 th:replace都是加载代码块内容,但是还是有所不同,下面会展示两者不同。
/templates/template/footer.html:
~~~
<!-- th:fragment 定义用于加载的块 -->
<span th:fragment="copy"> 2017 hry loaded by fragment=copy</span>
~~~
/templates/template/template.html:
th:include:加载模板的内容: 读取加载节点的内容(不含节点名称),替换div内容
th:replace:替换当前标签为模板中的标签,加载的节点会整个替换掉加载他的div
~~~
================= th:include 和 th:replace============================
<!-- 加载模板的内容: 读取加载节点的内容(不含节点名称),替换<div>的内容 -->
<div th:include="template/footer::copy">1</div>
<!-- 替换当前标签为模板中的标签: 加载的节点会整个替换掉加载他的<div> -->
<div th:replace="template/footer::copy">2</div>
~~~
运行结果输出:
~~~
<!-- 加载模板的内容: 读取加载节点的内容(不含节点名称),替换<div>的内容 -->
<div> 2017 hry loaded by fragment=copy</div>
<!-- 替换当前标签为模板中的标签: 加载的节点会整个替换掉加载他的<div> -->
<span> 2017 hry loaded by fragment=copy</span>
~~~
## 参数化模板配置
th:fragment定义模板的时候可以定义参数:
~~~
<div th:fragment="frag (onevar,twovar)">
<p th:text="${onevar} + ' - ' + ${twovar}">...</p>
</div>
~~~
在 th:include 和 th:replace中我们可以这样传参:
~~~
<div th:include="::frag (${value1},${value2})">...</div>
<div th:include="::frag (onevar=${value1},twovar=${value2})">...</div>
~~~
此外,定义模板的时候签名也可以不包括参数:`<div th:fragment="frag">`,我们任然可以通过`<div th:include="::frag (onevar=${value1},twovar=${value2})">...</div>`这种方式调用模板。这其实和<div th:include="::frag" th:with="onevar=${value1},twovar=${value2}">起到一样的效果
## th:assert 断言
我们可以通过th:assert来方便的验证模板参数
`<header th:fragment="contentheader(title)" th:assert="${!#strings.isEmpty(title)}">...</header>`
th:remove 删除代码
假设我们有一个产品列表模板:
~~~
<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>IN STOCK</th>
<th>COMMENTS</th>
</tr>
<tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
<td>
<span th:text="${#lists.size(prod.comments)}">2</span> comment/s
<a href="comments.html"
th:href="@{/product/comments(prodId=${prod.id})}"
th:unless="${#lists.isEmpty(prod.comments)}">view</a>
</td>
</tr>
</table>
~~~
## th:remove属性
通过`th:remove`属性,可以删除模板里的一些代码,让前端的多余的演示代码消失。
~~~
<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>IN STOCK</th>
<th>COMMENTS</th>
</tr>
<tr th:each="prod : ${prods}" th:class="${prodStat.odd}? 'odd'">
<td th:text="${prod.name}">Onions</td>
<td th:text="${prod.price}">2.41</td>
<td th:text="${prod.inStock}? #{true} : #{false}">yes</td>
<td>
<span th:text="${#lists.size(prod.comments)}">2</span> comment/s
<a href="comments.html"
th:href="@{/product/comments(prodId=${prod.id})}"
th:unless="${#lists.isEmpty(prod.comments)}">view</a>
</td>
</tr>
<tr class="odd" th:remove="all">
<td>Blue Lettuce</td>
<td>9.55</td>
<td>no</td>
<td>
<span>0</span> comment/s
</td>
</tr>
<tr th:remove="all">
<td>Mild Cinnamon</td>
<td>1.99</td>
<td>yes</td>
<td>
<span>3</span> comment/s
<a href="comments.html">view</a>
</td>
</tr>
</table>
~~~
其中th:remove的参数有如下几种:
~~~
all 删除当前标签和其内容和子标签
body 不删除当前标签,但是删除其内容和子标签
tag 删除当前标签,但不删除子标签
all-but-first 删除除第一个子标签外的其他子标签
none 啥也不干
~~~
当然,我们也可以通过表达式来传参,
`<a href="/something" th:remove="${condition}? tag : none">Link text not to be removed</a>`