PS:原文首发于微信公众号:躬行之(jzman-blog)
前面几篇文章尝试了接口开发、Thymeleaf 模板及其常用语法,阅读本文之前可以阅读前面几篇:
Thymeleaf 模板布局主要是为了更好的对前端页面进行划分,主要是通过 Thymeleaf 相关语法来对前端页面布局,主要内容如下:
- 引用模板片段
- 片段表达式语法
- 参数化模板片段
- 移除模板片段
- 模板布局继承
引用模板片段
使用 th:fragment
可以定义布局片段供其他页面引用,在 foter.html 中定义模板片段如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Footer</title>
</head>
<body>
<!--定义布局片段-->
<div th:fragment="copy">
© 2020 躬行之
</div>
</body>
</html>
上面定义了一个名为 copy 的片段,可以使用 th:insert
、 th:replace
和 th:include
来移入模板片段,其中 th:include
在 Thymeleaf 3.0 之后就不再推荐使用,在 home.html 中引入模板片段如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Template Layout.</title>
</head>
<body>
<!--引入模板片段-->
<div th:insert="~{footer::copy}"></div>
</body>
</html>
运行项目,查看 http://localhost:8080/home
,参考如下:
© 2020 躬行之
© 2020 躬行之
下面来看一下 th:insert
、 th:replace
和 th:include
三个之间的区别,使用三种方式分别引入名称为 copy
的模板片段如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Template Layout.</title>
</head>
<body>
<!--th:insert、th:replace、th:include的区别-->
<p>---th:insert、th:replace、th:include的区别---</p>
<!--直接插入模板片段-->
<div id="insert" th:insert="~{footer::copy}">insert</div>
<!--直接替换当前片段-->
<div id="replace" th:replace="~{footer::copy}">replace</div>
<!--直接插入指定片段的内容到当前片段中-->
<div id="include" th:include="~{footer::copy}">include</div>
</body>
</html>
上述代码中三个 div
分别设置了对应的 id
为 insert
、replace
和 include
,运行项目之后在浏览器查看源代码如下:
<!--...-->
<!--th:insert、th:replace、th:include的区别-->
<p>---th:insert、th:replace、th:include的区别---</p>
<div id="insert">
<div>
© 2020 躬行之
</div>
</div>
<div>
© 2020 躬行之
</div>
<div id="include">
© 2020 躬行之
</div>
<!--...-->
可知三者区别如下:
th:insert
:直接插入模板片段;th:replace
:直接替换当前片段;th:include
:直接插入指定片段的内容到当前片段中。
片段表达式语法
模板主要使用了片段表达式,片段表达式语法如下:
〜{templatename::selector}
:引入指定模板指定片段名称的模板片段;〜{templatename}
:引入指定模板的所有片段;〜{:: selector}
:同〜{this:: selector}
,引入当前模板指定名称的模板片段。
其中 templatename
表示模板名称,如上文中的 footer
,selector
表示片段名称,如上文中的 copy
。
此外 selector
也可以是 ID 选择器、类选择器以及标签,这样就可以在没有定义 th:fragment
的情况下使用相关模板片段了,如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Footer</title>
</head>
<body>
<div id="head">
<p>在没有定义th:fragment的情况下使用片段表达式--id</p>
</div>
<div class="head">
<p>在没有定义th:fragment的情况下使用片段表达式--class</p>
</div>
<div >
<span>在没有定义th:fragment的情况下使用片段表达式--span</span>
</div>
</body>
</html>
可在另一个模板中使用上述相应的代码片段,如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Template Layout.</title>
</head>
<body>
<!--在没有定义th:fragment的情况下使用片段表达式-->
<div th:insert="~{footer::#head}"></div>
<div th:insert="~{footer::.head}"></div>
<div th:insert="~{footer::span}"></div>
</body>
</html>
运行项目,结果如下:
在没有定义th:fragment的情况下使用片段表达式--id
在没有定义th:fragment的情况下使用片段表达式--class
在没有定义th:fragment的情况下使用片段表达式--span
参数化模板片段
在使用 th:fragment
定义模板片段的时候可以添加参数,如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Footer</title>
</head>
<body>
<!--在模板片段中添加参数-->
<div th:fragment="frag(name)" th:assert="${!#strings.isEmpty(name)}">
<p th:text="公众号名称+':'+${name}">Default</p>
</div>
</body>
</html>
然后在对应的页面引用上述片段就可以传递对应参数,如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Template Layout.</title>
</head>
<body>
<!--参数化模板片段-->
<div th:insert="~{footer::frag(${gzh})}"></div>
<!--这种写法如果有多个参数,顺序可以变化-->
<div th:insert="~{footer::frag(name=${gzh})}"></div>
</body>
</html>
上述代码中参数值 gzh=躬行之
,运行项目,结果如下:
公众号名称:躬行之
公众号名称:躬行之
其中可以在模板片段中使用 th:assert
属性来进行参数验证,也就是只有 th:assert
里面的表达式的值都为 true
才会继续执行,否则则会抛出异常。
移除模板片段
移除模板片段使用的是 th:remove
属性,该属性可设置的值如下:
- all: 移除所在标签以及所有的子标签;
- body: 不移除所在标签,只移除对应的子标签;
- tag: 只移除所在标签,不删除其子标签;
- all-but-first: 移除所在标签除第一个之外的所有子标签;
- none : 无任何移除操作。
具体使用方式参考如下:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>COMMENT</th>
</tr>
<!--移除所在标签以及所有的子标签-->
<tr th:remove="all">
<td>A</td>
<td>1</td>
<td>AA</td>
</tr>
<!--不移除所在标签,只移除对应的子标签-->
<tr th:remove="body">
<td>B</td>
<td>2</td>
<td>BB</td>
</tr>
<!--只移除所在标签,不删除其子标签-->
<tr th:remove="tag">
<td>C</td>
<td>3</td>
<td>CC</td>
</tr>
<!--移除所在标签除第一个之外的所有子标签-->
<tr th:remove="all-but-first">
<td>D</td>
<td>4</td>
<td>DD</td>
</tr>
<!--无任何移除操作-->
<tr th:remove="none">
<td>E</td>
<td>5</td>
<td>EE</td>
</tr>
</table>
</body>
</html>
主要关注 th:remove
属性设置不同的值运行后的效果,相当于如下页面:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table>
<tr>
<th>NAME</th>
<th>PRICE</th>
<th>COMMENT</th>
</tr>
<!--移除所在标签以及所有的子标签-->
<!--不移除所在标签,只移除对应的子标签-->
<tr></tr>
<!--只移除所在标签,不删除其子标签-->
<td>C</td>
<td>3</td>
<td>CC</td>
<!--移除所在标签除第一个之外的所有子标签-->
<tr>
<td>D</td>
</tr>
<!--无任何移除操作-->
<tr>
<td>E</td>
<td>5</td>
<td>EE</td>
</tr>
</table>
</body>
</html>
模板布局继承
模板布局继承使用的还是 th:fragment
和 th:replace
,下面通过案例演示一下模板布局继承的写法,定义要继承的页面如下:
<!DOCTYPE html>
<html th:fragment="layout (title, content)" xmlns:th="http://www.thymeleaf.org">
<head>
<title th:replace="${title}">Layout Title</title>
</head>
<body>
<h1>Layout H1</h1>
<div th:replace="${content}">
<p>Layout content</p>
</div>
<footer>
Layout footer
</footer>
</body>
</html>
继承上述页面的文件将会替换上述 title
和 content
的值,继承上述页面写法如下:
<!DOCTYPE html>
<html th:replace="~{base :: layout(~{::title}, ~{::section})}" xmlns:th="http://www.thymeleaf.org">
<head>
<title>Page Title</title>
</head>
<body>
<section>
<p>Page content</p>
<div>Included on page</div>
</section>
</body>
</html>
运行后的效果如下:
Layout H1
Page content
Included on page
Layout footer
可关注公众号【躬行之】交流学习,点击查看源码。