ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 概述 在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"> &copy; 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>`