thymeleaf简单使用
thymeleaf是SpringBoot默认集成的模板引擎
表达式
${...}
: 变量表达式。
*{...}
: 选择表达式。
#{...}
: 消息 (i18n) 表达式。
@{...}
: 链接 (URL) 表达式。
~{...}
: 片段表达式。
使用thymeleaf抽取公共片段
使用th:fragment="xx"
来抽取某个页面的片段
<div th:fragment="copy">
</div>
使用th:insert="~{page::xx}"
来引入从page中抽取的片段
<div th:insert="~{dashboard::copy}">
</div>
此时抽取部分被包含在一个div中。有可能造成排版错乱
三种引入片段的属性
th:insert
:将公共的片段整个插入指定元素中
th:replace
:将声明引入的元素替换为公共片段(符合理想情况)
th:include
:将被引入公共片段的内容插入到指定的元素中
如果使用th:insert属性引入则可以不用写~{},例如th:insert="dashboard::copy"
而行内写法则必须加上~{}
:[[~{}]]
、[(~{})]
还可以不使用th:fragment
抽取公共部分,在引入的页面中使用th:replace="~{template::#selector}"
即可
在博客系统中抽取公共片段
以首页为例,其它页面用法稍有不同。
新建一个admin_fragments.html
,存放admin文件夹中页面的公共部分;
新建一个fragments.html
页面,里面保存公共片段。
将这两个文件统一放到templates下的commons文件夹下。
CSS样式
先将所有页面引入的css保存起来,在别的页面引入时,只需要传入参数改变页面的title
属性即可。
fragments.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:fragment="head(title)">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>[[${title}]]</title>
<link rel="stylesheet" href="/css/me.css" th:href="@{/css/me.css}">
<link rel="stylesheet" href="/css/typo.css" th:href="@{/css/typo.css}">
<link rel="stylesheet" href="/lib/editormd/css/editormd.css" th:href="@{/lib/editormd/css/editormd.css}" />
<link rel="stylesheet" href="/lib/tocbot/tocbot.css" th:href="@{/lib/tocbot/tocbot.css}">
<link rel="stylesheet" href="/lib/prism/prism.css" th:href="@{/lib/prism/prism.css}">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.css">
</head>
<body>
</body>
</html>
在首页传入titile
的值为'首页'
,则页面标题为"首页",例如:
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="_fragments::head('首页')"></head>
<body>
...
</body>
</html>
导航栏
大部分页面(除博客管理和写博客页面)的头部是一样的,只是active的地方不同而已。
fragments.html
<body>
<!-- 导航 -->
<nav th:fragment="menu(index)" class="ui inverted attached segment m-padding-tb-mini m-shadow-small" id="header">
<div class="ui container m-container-large">
<div class="ui inverted secondary stackable menu">
<h2 class="ui teal header item m-header">Yonmin</h2>
<a href="/" class="m-item item m-mobile-hide" th:classappend="${index=='首页'} ? 'active'"><i class="home icon"></i>首页</a>
<a href="types" class="m-item item m-mobile-hide" th:classappend="${index=='分类'} ? 'active'"><i class="idea icon"></i>分类</a>
<a href="tags" class="m-item item m-mobile-hide" th:classappend="${index=='标签'} ? 'active'"><i class="tags icon"></i>标签</a>
<a href="archives" class="m-item item m-mobile-hide" th:classappend="${index=='归档'} ? 'active'"><i class="clone icon"></i>归档</a>
<a href="about" class="m-item item m-mobile-hide" th:classappend="${index=='关于我'} ? 'active'"><i class="info icon"></i>关于我</a>
<div class="right item m-item m-mobile-hide m-margin-tb-small">
<div class="ui icon inverted transparent input">
<input type="text" placeholder="Search...">
<i class="search link icon"></i>
</div>
</div>
</div>
</div>
<a href="#" class="ui button black icon m-top-right m-mobile-show show">
<i class="sidebar icon"></i>
</a>
</nav>
根据传入的index
值选择在哪个元素的class中添加active,因此只需要在页面传入相应的值即可。
例如首页写<head th:replace="_fragments::head('首页')"></head>
分类页写<head th:replace="_fragments::head('分类')"></head>
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="_fragments::head('首页')"></head>
<body>
<!-- 导航 -->
<div th:replace="_fragments::menu('首页')"></div>
...
<body>
</html>
底部 footer
底部footer除了博客管理页面(因为无用所以我将其删除了)和写博客页面外的所有页面都是一样的,只需要抽取后直接在页面内引入。
fragments.html
<!-- 底部footer -->
<footer th:fragment="footer" id="footer" class="ui inverted vertical segment m-padding-tb-massive">
<div class="ui center aligned container m-container-large">
<div class="ui grid stackable inverted divided">
<div class="three wide column">
<div class="ui inverted link list">
<div class="item">
<img src="images/wechat.jpg" class="ui rounded image" style="width: 110px">
</div>
</div>
</div>
<div class="three wide column">
<h4 class="ui inverted header m-opacity-mini">最新博客</h4>
<div class="ui inverted link list">
<a href="#" class="item">用户故事</a>
<a href="#" class="item">用户故事</a>
<a href="#" class="item">用户故事</a>
</div>
</div>
<div class="three wide column">
<h4 class="ui inverted header m-opacity-mini">联系我</h4>
<div class="ui inverted link list">
<a href="#" class="item">Email:2@qq.com</a>
<a href="#" class="item">WeChat:YonminMa</a>
<a href="#" class="item">QQ:2</a>
</div>
</div>
<div class="seven wide column">
<h4 class="ui inverted header m-opacity-mini">Blog</h4>
<p class="m-text-thin m-text-spaced m-opacity-mini">这是我的个人博客、分享关于编程、写作、思考相关的任何内容,希望可以给来这儿的人一点帮助。。。</p>
</div>
</div>
<div class="ui inverted section divider"></div>
<p class="m-text-thin m-text-spaced m-opacity-tiny">Copyright © 2012-2020 Yonmin. All Rights Reserved.</p>
</div>
</footer>
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="_fragments::head('首页')"></head>
<body>
<!-- 导航 -->
<div th:replace="_fragments::menu('首页')"></div>
...
<!-- 底部footer -->
<div th:replace="_fragments::footer"></div>
...
</body>
</html>
admin_fragments.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:fragment="head(title)">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>[[${title}]]</title>
<link rel="stylesheet" href="/css/me.css" th:href="@{/css/me.css}">
<link rel="stylesheet" href="/css/typo.css" th:href="@{/css/typo.css}">
<link rel="stylesheet" href="/lib/editormd/css/editormd.css" th:href="@{/lib/editormd/css/editormd.css}">
<link rel="stylesheet" href="/lib/tocbot/tocbot.css" th:href="@{/lib/tocbot/tocbot.css}">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.css">
</head>
<body>
<nav th:fragment="menu(index)" class="ui inverted attached segment m-padding-tb-mini m-shadow-small" id="header">
<div class="ui container m-container-large">
<div class="ui inverted secondary stackable menu">
<h2 class="ui teal header item m-header">Yonmin</h2>
<a href="#" class="m-item item m-mobile-hide" th:classappend="${index=='博客'} ? 'active'"><i class="home icon"></i>博客</a>
<a href="#" class="m-item item m-mobile-hide" th:classappend="${index=='分类'} ? 'active'"><i class="idea icon"></i>分类</a>
<a href="#" class="m-item item m-mobile-hide" th:classappend="${index=='标签'} ? 'active'"><i class="tags icon"></i>标签</a>
<div class="right m-item m-mobile-hide menu">
<div class="ui dropdown item">
<img src="https://tse4-mm.cn.bing.net/th/id/OIP.Ie53C-X76KBg5Yr5rf6JbgHaDe?w=318&h=164&c=7&o=5&pid=1.7" alt="" class="ui avatar image">
<!-- <div>Yonmin</div>-->
<!-- <i class="dropdown icon"></i>-->
<div class="menu">
<a href="/admin/logout" class="item">注销</a>
</div>
</div>
</div>
</div>
</div>
<a href="#" class="ui button black icon m-top-right m-mobile-show show">
<i class="sidebar icon"></i>
</a>
</nav>
</body>
</html>
对导航栏样式做了少许修改。
使用时用例如<div th:replace="commons/admin_fragments::menu('博客')"></div>
引用。
引入的js资源也是可以抽取的,但是不多,我就没弄,有需要的朋友可以自己抽取一下。
此更新已提交至此项目的Github,欢迎star