Thymeleaf模板 页面布局(Page Layouts)
恩
Thymeleaf标准布局系统
1.基础的
让我们简短的分析下包含语句:
<div th:replace="fragments/header :: header">...</div>
fragments/header
即为 fragments/header.html
是我们正在引用的模板文件的名称,双冒号后面的表达式header
是一个 fragment 选择器 。
文件 :fragments/header.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
...
</head>
<body>
<!--在这里指定 fragment -->
<div th:fragment="header1">
<p>我是header1</p>
</div>
...
<div th:fragment="header2">
<p>我是header2</p>
</div>
</body>
然后在其他HTML中:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
...
</head>
<body>
...
<!--引用 th:fragment="header1"-->
<div th:replace="fragments/header :: header1">...<div>
</body>
就把第一个 div 引用过来了,通过这种方式,我们可以在一个模板文件中定义多个片段,就像上面做的那样。
这里重要的是,所有的模板仍然可以是自然模板,并且可以在没有运行服务器的浏览器中查看。
2.通过标记选择器
通过使用标记选择器语法,类似 jQuery 选择器,thymeleaf 可以选择任意部分作为片段,而不用事先标记。
标记选择器语法地址
<div th:insert="https://www.thymeleaf.org :: div.description" >...</div>
上面的代码将包含一个来自thymeleaf.org 的 class=“description” 的 div 。
为了实现这一点,模板引擎必须配置为 UrlTemplateResolver 如下:
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.addTemplateResolver(new UrlTemplateResolver());
...
return templateEngine;
}
3.使用表达式
在 templatename :: selector
中, templatename
和selector
都可以是表达式。
<div th:replace="fragments/header:: ${#authentication.isAdmin()} ? 'header1' : 'header2'">
© 2016 The Static Templates
</div>
4.带参数的
显式定义:
<!--在这里定义带参数的 th:fragment="alert (type, message)"-->
<div th:fragment="alert (type, message)" th:assert="${!#strings.isEmpty(type)
and !#strings.isEmpty(message)}" class="alert alert-dismissable" th:classappend="'alert-' + ${type}">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<span th:text="${message}">Test</span>
</div>
其他页面使用的时候传递参数给它:
<th:block th:if="${message != null}">
<div th:replace="fragments/alert :: alert (type=${#strings.toLowerCase(message.type)},
message=#{${message.message}(${#authentication.name})})"> </div>
</th:block>
5.Fragment 表达式
Thymeleaf 3.0 新增方式
task/layout.html
页面:
<head th:fragment="head(title, links, scripts)">
<title th:replace="${title}">Task List</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link href="../../../resources/css/bootstrap.min.css" rel="stylesheet" media="screen"
th:href="@{/resources/css/bootstrap.min.css}"/>
<link href="../../../resources/css/core.css" rel="stylesheet" media="screen"
th:href="@{/resources/css/core.css}"/>
<!--/* Per-page placeholder for additional links */-->
<th:block th:replace="${links}" />
<!--/* Per-page placeholder for additional scripts */-->
<th:block th:replace="${scripts}" />
其他页面:
<head th:replace="task/layout :: head(~{this :: title}, ~{this :: .custom-link}, ~{this :: .custom-script})">
<title>Task Details</title>
<!-- 这块相同的就是`task/layout`页面共有的 -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link href="../../../resources/css/bootstrap.min.css" rel="stylesheet" media="screen" th:href="@{/resources/css/bootstrap.min.css}"/>
<link href="../../../resources/css/core.css" rel="stylesheet" media="screen" th:href="@{/resources/css/core.css}"/>
<!-- Custom links for this page only -->
<link class="custom-link" href="../../../resources/css/task/task.css" th:href="@{/resources/css/task/task.css}" />
<!-- Custom scripts for this page only -->
<script class="custom-script" src="../../../resources/js/task/task.js" th:src="@{/resources/js/task/task.js}"></script>
</head>
1.这个表达式灵活的地方就在于既拿到了模板页面的东西,又在模板页面的基础上添加了自己独有的东西。
2.单独打开task/layout.html
页面会报错。
来自Spring @Controller的 fragment
页面点击注册按钮弹出模态框:
<script th:inline="javascript" type="text/javascript">
/* Fill in modal with content loaded with Ajax */
$(document).ready(function () {
$('#signup').on('click', function (e) {
$("#myModal").modal();
$("#myModalBody").text("");
$.ajax({
url: "signup",
cache: false
}).done(function (html) {
$("#myModalBody").append(html);
});
})
});
</script>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">Signup</h4>
</div>
<div class="modal-body" id="myModalBody">Lorem ipsum</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
可以看出上面的模态框内容是空白的,显示的内容是由ajax返回的数据。
在 signup/signup.html
定义返回的 html (th:fragment="signupForm"
):
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
<form method="post"
th:action="@{/signup}" th:object="${signupForm}" th:fragment="signupForm">
...
</form>
</body>
</html>
在Controller中返回的字符串为 signup/signup :: signupForm
指向了上面这个
private static final String SIGNUP_VIEW_NAME = "signup/signup";
@RequestMapping(value = "signup")
public String signup(Model model,
@RequestHeader("X-Requested-With") String requestedWith) {
model.addAttribute(new SignupForm());
if (AjaxUtils.isAjaxRequest(requestedWith)) {
return SIGNUP_VIEW_NAME.concat(" :: signupForm");
}
return SIGNUP_VIEW_NAME;
}
效果查看需要在服务器上运行(官网说这个 Thymol 可以在不运行的时候查看 有时间再看吧)
Thymeleaf Layout Dialect
1.配置
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>2.0.5</version>
</dependency>
我们还需要通过在模板引擎中添加额外的配置:
@Bean
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
...
templateEngine.addDialect(new LayoutDialect());
return templateEngine;
}
2.创建一个布局
task-ld/layout.html
创建layout:fragment="content"
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>...</head>
<body>
<div th:replace="fragments/header :: header"></div>
<div class="container">
<!--在这里设置layout布局-->
<div layout:fragment="content">...</div>
<div th:replace="fragments/footer :: footer">© 2017 The Static Templates</div>
</div>
</body>
</html>
在task-ld/task-list.html
页面引用:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{task-ld/layout}">
<head></head>
<body>
<div layout:fragment="content">...</div>
</body>
</html>
注意
<html>
元素中的layout:decorate="~{task-ld/layout}"
task-list.html
中的layout:fragment="content"
会替换layout.html
中的。其他东西继承过来。比如头尾。
task-list.html
页面没有layout布局的时候:
task-list.html页面有layout布局的时候:可以看出多了 头和尾
Include style approach with Layout Dialect
task-ld/alert.html
页面设置layout:fragment
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<body>
<th:block layout:fragment="alert">
<div class="alert alert-dismissable" th:classappend="'alert-' + ${type}">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<h4 th:text="${header}">Alert header</h4>
<!--/* 'layout:fragment' attribute defines a replaceable content section */-->
<th:block layout:fragment="alert-content">
<p>Default alert content</p>
</th:block>
</div>
</th:block>
</body>
</html>
在task-ld/task-list.html
页面调用:
<div layout:insert="~{task-ld/alert :: alert}" th:with="type='info', header='Info'" th:remove="tag">
<!--/* Implements alert content fragment with simple content */-->
<th:block layout:fragment="alert-content">
<p><em>This is a simple list of tasks!</em></p>
</th:block>
</div>
或者:
<div layout:insert="~{task-ld/alert :: alert}" th:with="type='danger', header='Oh snap! You got an error!'" th:remove="tag">
<!--/* Implements alert content fragment with full-blown HTML content */-->
<th:block layout:fragment="alert-content">
<p>Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Cras mattis consectetur purus sit amet fermentum.</p>
<p>
<button type="button" class="btn btn-danger">Take this action</button>
<button type="button" class="btn btn-default">Or do this</button>
</p>
</th:block>
</div>
还是看这幅图,样式都调用到了,内容做了替换。
关于thymeleaf th:replace th:include th:insert 的区别
th:insert :保留自己的主标签,保留th:fragment的主标签。
th:replace :不要自己的主标签,保留th:fragment的主标签。
th:include :保留自己的主标签,不要th:fragment的主标签。(官方3.0后不推荐)
这是第一篇博客,看的是tylmeleaf布局相关,后面继续看Thymeleaf的文档。ヾ(◍°∇°◍)ノ゙加油。