Thymeleaf 模板布局 th:fragment、th:replace、th:insert、th:remove
th:fragment 模板布局
模板片段说明
模板中,经常希望从其他模板中包含⼀些部分,如⻚眉,⻚脚,公共菜单等部分,为了做到这⼀点,Thymeleaf 可以使⽤th:fragment 属性来定义被包含的模版⽚段,以供其他模版包含。
如下所示定义模板片段:
<div th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</div>
上⾯的代码定义了⼀个名为 copy 的⽚段,然后可以使⽤ th:insert 或 th:replace属性轻易地包含进需要的页面中。
<div th:insert="~{commons :: copy}"></div>
<div th:replace="~{commons :: copy}"></div>
- commons:表示模板名称,就是 html 文件的名称,如果是 springboot 开发,则根据 Spring Boot 配置的 Thymeleaf 映射查找。
- copy:表示模板片段名称,即 th:fragment=“copy” 的名称
th:insert、th:replace 中的 〜{…} 表示⽚段表达式,它是可选的,上⾯的代码等价于如下所示写法,这也是实际开发中常用的写法:
<div th:insert="commons :: copy"></div>
<div th:replace="commons :: copy"></div>
⽚段表达式语法
1、被引用的 th:fragment 模板片段与引用的 th:insert 或 th:replace 可以是在同一个 Html 文件中,也可以不在同一个 html 中。
⽚段表达式语法⾮常简单,有如下三种不同的格式:
- 1)〜{templatename :: selector} -:- templatename 表示模板名称(html 文件名称),springboot 项目中就是 “templates”目录下的 html 文件名称,它根据 springboot 对 thymeleaf 的规则进行映射。selector 即可以是 th:fragment 定义的片段名称,也可以选择器,如标签的 id 值、CSS 选择器、或者 XPath 等。
- 2)〜{templatename} -:- 包含名为 templatename 的整个模板。
- 3)〜{:: selector} 或 〜{this :: selector}:包含在同⼀模板中的指定选择器的⽚段
模板名 templatename 和选择器 selector 都可以是表达式(甚⾄是条件表达式!)如:
<div th:replace="commons :: (${isAdmin}? f1 : f2)"></div>
<div th:fragment="f1">
<p>f111111111111</p>
</div>
<div th:fragment="f2">
<p>f22222222222</p>
</div>
================== fragment语法 =============================
<!-- 语法说明 "::"前面是模板文件名,后面是选择器 -->
<div th:include="template/footer::copy"></div>
<!-- 只写选择器,这里指fragment名称,则加载本页面对应的fragment -->
<div th:include="::#thispage"></div>
<!-- id选择器 -->
<div th:insert="~{footer :: #copy-section}"></div>
<!-- 只写模板文件名,则加载整个页面 -->
<div th:include="template/footer"></div>
================= 加载块 ============================
<span id="thispage">
div in this page.
</span>
th:insert 与 th:replace 区别
- th:insert:将被引用的模板片段插⼊到自己的标签体中
- th:replace:将被引用的模板片段替换掉自己
<!--1、比如抽取的公用代码片段如下-->
<footer th:fragment="copy">
© 2011 The Good Thymes Virtual Grocery
</footer>
<!--2、采用如下三种方式进行引用-->
<div th:insert="footer :: copy"></div>
<div th:replace="footer :: copy"></div>
<div th:include="footer :: copy"></div>
<!--3、则三种引用方式的效果分别对应如下-->
<div>
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
</div>
<footer>
© 2011 The Good Thymes Virtual Grocery
</footer>
<div>
© 2011 The Good Thymes Virtual Grocery
</div>
th:insert 、th:replace、th:include 在标签中进行引用时可以不用片段表达式 〜{…} ,但是行内写法时,必须要用片段表达式,如:[[{}]]、[({})]
参数化片段签名
为了使模板⽚段具有类似函数的功能,th:fragment 定义的⽚段可以指定⼀组参数:
<div th:fragment="frag (onevar,twovar)">
<p th:text="${onevar} + ' - ' + ${twovar}">...</p>
</div>
于是在 th:insert、th:replace 引用模板片段的时候,就可以传递参数过去:
//按参数定义时的顺序进行传递
<div th:replace="templatename :: frag (${value1},${value2})">...</div>
//按参数名称传递,此时与参数定义的顺序无关
<div th:replace="templatename :: frag (onevar=${value1},twovar=${value2})">...</div>
比如公共菜单中高亮显示当前菜单时就可以使用这种传递参数的方式进行标识当前活动的菜单。
结合layui布局后台管理系统
1、静态文件目录
2、编写公共模板(commons.html)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<meta charset="UTF-8">
<title>公共模板</title>
</head>
<!--定义公共的头部,commonHeader 为模板片段名称-->
<header th:fragment="commonHeader">
<link type="text/css" rel="stylesheet" th:href="@{/layui/css/layui.css}">
<script th:src="@{/layui/layui.all.js}"></script>
<div class="layui-header">
<div class="layui-logo"><a href="">后台管理系统</a></div>
</div>
</header>
<!-- 定义公共的左侧菜单,commonMenu 表示片段名称,index 为传递进来的参数-->
<menu th:fragment="commonMenu(index)">
<div class="layui-side layui-bg-black">
<div class="layui-side-scroll">
<ul class="layui-nav layui-nav-tree">
<li class="layui-nav-item layui-nav-itemed">
<dl class="layui-nav-child">
<!-- 根据传递的参数 index 来设置当前活动的菜单样式;三元运算符,第三个参数缺省,当 ? 判断为 false 时返回 null-->
<dd th:class="${index}==0?'layui-this'"><a th:href="@{/content1}">菜单1</a></dd>
<dd th:class="${index}==1?'layui-this'"><a th:href="@{/content2}">菜单2</a></dd>
<!-- 同理如果还有其它更多的菜单时,可以依次往下传递参数-->
</dl>
</li>
</ul>
</div>
</div>
</menu>
<!--定义公共的底部,这里使用 id 选择器,当然也可以用片段名,如 th:fragment="commonFooter"-->
<footer id="commonFooter">
<div class="layui-footer">
<p>Copyright © 1998 - 2018 YYServer. All Rights Reserved</p>
</div>
</footer>
</html>
3、编写内容主体
content1.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>后台管理</title>
</head>
<body class="layui-layout-body">
<div class="layui-layout layui-layout-admin">
<header th:replace="commons :: commonHeader"></header>
<menu th:replace="commons :: commonMenu(0)"></menu>
<div class="layui-body">
<!-- 内容主体区域 -->
<div style="padding: 15px;">
<p>内容主体区域1</p>
</div>
</div>
<footer th:replace="commons :: #commonFooter"></footer>
</div>
</body>
</html>
content2.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>后台管理</title>
</head>
<body class="layui-layout-body">
<div class="layui-layout layui-layout-admin">
<header th:replace="commons :: commonHeader"></header>
<menu th:replace="commons :: commonMenu(1)"></menu>
<div class="layui-body">
<!-- 内容主体区域 -->
<div style="padding: 15px;">
<p>内容主体区域2</p>
</div>
</div>
<footer th:replace="commons :: #commonFooter"></footer>
</div>
</body>
</html>
4、编写控制器
@Controller
public class HelloController {
@RequestMapping("/content1")
public String content1(Map<String, Object> paramMap) {
System.out.println("content1");
return "content1";
}
@RequestMapping("/content2")
public String content2(Map<String, Object> paramMap) {
System.out.println("content2");
return "content2";
}
}
5、测试效果图