SpringBoot使用thymeleaf实现布局方案一,不懂就out了(循序渐进的超级详细讲解方式) - 第424篇
在搭建一个网页的时候,一般的会分为header、content、footer,也就是导航部分、中间的内容部分、以及底部。对于header和footer这两个部分一般的是很多页面公用的,那么这时候,我们会把公共的部分进行抽离出来,这就是所谓的thymeleaf布局。
这一节就到大家来看看其中的一种布局方案。
一、准备工作
在具体讲解布局方案之前,我们一起先来大家一个基本的页面,包含header、content以及footer。
在具体的讲解之前,说明一下基本的环境:
(1)OS:Mac OS
(2)Spring Boot版本:2.6.7
(3)JDK:1.8
(4)thymeleaf:3.0
在使用idea构建的时候,默认选择的是11。现在都jdk十几了,我是不是有必要也升级到比较新的版本呢?亲爱的粉丝,你们觉得呢?
1.1 构建项目
使用Idea工具构建一个spring boot项目,取名为springboot-thymeleaf-layout。
啥,你说你不喜欢这个名称,那你随意,只要你开心,想取啥就取啥,O(∩_∩)O哈哈~
1.2 页面映射
编写一个Controller,当访问/index的时候,访问index.html页面
package com.kfit.website.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
*
* 官网的控制器
*
* @author 悟纤「公众号SpringBoot」
* @date 2022-04-23
* @slogan 大道至简 悟在天成
*/
@Controller
public class WebsiteController {
/**
* 跳转到首页页面
* @return
*/
@RequestMapping(value = {"/index","/"})
public String index(){
return "/index";
}
}
1.3 index.html页面
接下来就是页面了,在resources/templates先创建index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 导航部分 -->
<header style="text-align: center;height: 40px;background: cadetblue;"> 首页 | 产品 | 关于我们 </header>
<!-- 内容部分 -->
<div style="text-align: center;;height: 150px;">内容部分</div>
<!-- 顶部部分 -->
<footer style="text-align: center;;height: 40px;background: #2e2e41;color:white;">@版权所有 公众号SpringBoot</footer>
</body>
</html>
说明:在实际中,样式部分以及前端页面有前端工程师进行编写,这里仅仅是示例。当然你如果你也会前端技术的话,那么你就是别人家的孩子了——全栈架构师,牛牪犇逼。
1.4 启动测试
启动应用访问地址:
http://127.0.0.1:8080/index
二、使用include/replace/insert进行布局
在前端的<header>、<footer>是写在了index.html中,我们紧接着编写product.html,aboutus.html会发现它们也需要<header>、<footer>,而且基本上是大同小异,如果非得说有区别的话,那就是当前页面的的时候,可能会高亮。
那么我们就得思考,这样子的话<header>、<footer>就应该抽离出来变成公共的部分,当你在开发的时候,到这一步就能想到后面发生的很多步,以此来进行设计,这个就是架构,一不小心你还在开发工程师的时候,就拥有了架构思维。
那么公共部分怎么抽离出来呢,这就是本节的重点th:include和th:replace。
2.1 抽离出来header和footer
首先将header和footer抽离出来,定义两个页面header和footer。
对应的common/header.html代码:
<!-- 导航部分 -->
<header style="text-align: center;height: 40px;background: cadetblue;"> 首页 | 产品 | 关于我们 </header>
2.2 使用include/replace引入
接下来就是使用th:include/th:replace引入header.html和footer.html。
对于th:include/th:replace有什么区别呢?
(1)th:include:引入子模块的children,依然保留父模块的tag。加载模板的内容:读取加载节点的内容(不含节点名称),替换div内容
(2)th:replace:引入子模块的所有,不保留父模块的tag。替换当前标签为模板中的标签,加载的节点会整个替换掉加载他的div
先看下th:include的方式,在index.html的代码就会变成:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<header th:include="common/header.html"></header>
<!-- 内容部分 -->
<div style="text-align: center;;height: 150px;">内容部分</div>
<footer th:include="common/footer.html"></footer>
</body>
</html>
运行效果是一样的,主要看下th:include生成的源码:
依然保留父模块的tag<header>。加载模板的内容:读取加载节点的内容(不含节点名称),替换div内容
接下来看下th:replace的方式,在index.html的代码就会变成:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<header th:replace="common/header.html"></header>
<!-- 内容部分 -->
<div style="text-align: center;;height: 150px;">内容部分</div>
<footer th:replace="common/footer.html"></footer>
</body>
</html>
运行效果是一样的,主要看下th:replace生成的源码:
不保留父模块的tag<header>。替换当前标签为模板中的标签,加载的节点会整个替换掉加载他的div
2.3 thymleaf3.0的insert
Thymeleaf 3.0 之后不再推荐使⽤ th:include.
l th:insert:将被引用的模板片段插⼊到自己的标签体中
l th:replace:将被引用的模板片段替换掉自己
l th:include:类似于 th:insert,⽽不是插⼊⽚段,它只插⼊此⽚段的内容。
看下insert生成的效果:
可以看到这里的效果和th:include很类似,暂时看不出来区别。
2.4 th:fragment代码片段加载
对于header和footer可以单独一个页面,也可以在同一个页面,那么这时候,怎么确定要加载哪一部分呢?th:fragment就派上用场了。fragment有碎片; 片段之意,也就是定义一段代码碎片标识。
首先定义common.html,包含header.html和footer.html的代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 导航部分 -->
<header th:fragment="header" style="text-align: center;height: 40px;background: cadetblue;"> 首页 | 产品 | 关于我们 </header>
<!-- 顶部部分 -->
<footer th:fragment="footer" style="text-align: center;;height: 40px;background: #2e2e41;color:white;">@版权所有 公众号SpringBoot</footer>
</body>
</html>
说明:这里定义了代码片段header和footer,通过th:fragment进行指定。
仅紧着看下index.html的代码,也可以新建一个index2.html进行测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<header th:insert="common/common::header"></header>
<!-- 内容部分 -->
<div style="text-align: center;;height: 150px;">内容部分</div>
<footer th:insert="common/common::footer"></footer>
</body>
</html>
使用th:insert生成的源码:
使用th:include生成的源码:
<header标签的样式不见了,那么效果就会变成:
使用th:replace生成的源码:
从这里就可以看出th:insert和th:include的区别了?具体区别,自己仔细观察生成的源码,自行总结下。
到这里,我先说明一下,大部分情况下建议使用th:replace,可以看出生成的代码干净利落,不出现多余的父类标签。当然如果你的父类标签有样式的时候,那么就使用th:insert。
2.5 当前页面公用部分引入
在一个页面中,也会出现有些部分的代码样式是一样的,你可以把这部分叫做模板。
那么当前页面的样式如何引入呢?小子们上代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<header th:replace="common/common::header"></header>
<!-- 内容部分 -->
<div style="text-align: center;height: 150px;">内容部分</div>
<div th:include="::#pageCommon"></div>
<footer th:replace="common/common::footer"></footer>
<template id="pageCommon">
<div style="text-align: center;">页面公用部分</div>
</template>
</body>
</html>
说明:
(1)使用::#pageCommon,元素选择器的方式就可以引入了。
(2)<template>标签:标记用作容纳页面加载时对用户隐藏的 HTML 内容的容器。如果您有一些需要重复使用的 HTML 代码,则可以使用 <template> 标记。
效果:
此时生成的源代码:
这里就不能使用th:insert和th:replace了,看下生成的源码:
看源码会发现,此时<template>节点也被携带过来了,由于<template>隐藏特性,内容根本不会显示出来:
有人会问,我就是想喜欢th:replace,我们老大说只能使用th:replace,那么此时怎么破呢?这个也很好破,只需要稍微修改一个地方即可:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<header th:replace="common/common::header"></header>
<!-- 内容部分 -->
<div style="text-align: center;height: 150px;">内容部分</div>
<div th:replace="::#pageCommon"></div>
<footer th:replace="common/common::footer"></footer>
<template>
<div id="pageCommon" style="text-align: center;">页面公用部分</div>
</template>
</body>
</html>
细心的网页肯定发现了,我这里这是把id移动到了内部div上,这时候就可以使用th:replace了,看下生成的源码:
但是这里会引发出来一个新的问题,什么问题呐?我们在一开始说到到,对于<template>是页面的公共内容,那么很显然会被多处引入,而这里的div的id为pageCommon,很显然要对这个元素操作的时候就麻烦了。
那么针对这种情况怎么破呢?很简单,这里提供关键词:选择器。
2.6 参数传递
很多时候,我们的common.html也会有一些不一样的地方,比如首页激活的时候,会多出来一个class属性,那么一方面可以根据页面地址的不同进行条件的判断,另外一方面就是是否在引入代码的时候,是否可以引入参数呢?
需要先修改common.html,当然也可以复制出来一份common2.html,允许参数的传递:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 导航部分 -->
<header th:fragment="header(param1,param2)" style="text-align: center;height: 40px;background: cadetblue;">
首页 | 产品 | 关于我们 - <span th:text="${param1} +'--'+ ${param2}"></span>
</header>
<!-- 顶部部分 -->
<footer th:fragment="footer" style="text-align: center;;height: 40px;background: #2e2e41;color:white;">@版权所有 公众号SpringBoot</footer>
</body>
</html>
然后修改index.html进行参数传递,也可以复制出来一份index3.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<header th:replace="common/common2::header('/index.html',1000)"></header>
<!-- 内容部分 -->
<div style="text-align: center;height: 150px;">内容部分</div>
<footer th:replace="common/common2::footer"></footer>
</body>
</html>
效果:
可以获取到参数之后,那么就可以根据这些参数进行一些特殊的处理了。
总结
最后和大家总结下:
(1)布局方案th:include/th:replace/th:insert,其中include在thymeaf在3.0之后就不推荐使用了。
(2)代码片段th:fragment,在一个页面可以定义多段代码片段,以此通过th:replace=“common:: fragmentId”的方式引入不通过的代码片段。
(3)参数的传递:在使用th:fragment的时候,可以接一个参数列表。
这节就先到这里,对于th:include/th:replace/th:insert或者thymeleaf的使用你还有其它的疑问吗?请留言!
购买完整视频,请前往:http://www.mark-to-win.com/TeacherV2.html?id=287