赞
踩
由于之前项目是Springboot+VUE,但是VUE对于IE8及以下的浏览器存在兼容问题,所以最近可能需要重新做前端项目,不再前后端分离,而是在springboot里全部完成,由于springboot2.0以上已不再支持jsp文件,所以使用HTML+JQuery来重写前端,后端也使用springboot返回页面.但是对于页面布局.嵌套.异步刷新等问题不太熟悉.最近又重新学了一下thymleaf,这里准备做个记录.
提示:在IDEA中,开发页面时,可以通过ctrl+F9来重新build页面部分内容,无须重启项目来查看静态文件编辑效果
在Springboot中添加thymleaf和layout的依赖,在pom.xml中添加下面两个
<!-- thymleaf模板依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/nz.net.ultraq.thymeleaf/thymeleaf-layout-dialect -->
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>
第二个不确定需不需要,但是看大家都加了.所以也加上了!
之后就可以在Springboot项目中使用thymleaf了
这部分就参考thymleaf的各种文档吧,常用的就是th:text,th:value,th:each,th:if等等,很好懂.
因为只是尝试做简单的页面测试使用,所以使用IDEA画的HTML页面,在使用th:时,会提示我引入,但是看别的项目不写也能用
在文件头加上这句话
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
就可以使用th了
使用th:fragment定义一个模块,该模块可以在待使用的html文件中,也可以在其他html文件中.被th:fragment定义过的模块可以在其他地方通过th:include,th:insert,th:replace来引入进来
三种方式的区别:
th:insert :保留自己的主标签,保留th:fragment的主标签。
th:replace :不要自己的主标签,保留th:fragment的主标签。
th:include :保留自己的主标签,不要th:fragment的主标签。(官方3.0后不推荐)
举个栗子!
我定义一个mainModule.html文件,在里面写fragment的模块
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div th:fragment="head"> 这里是modules的head fragment </div> <div th:fragment="left"> 这里是modules的left fragment </div> <div th:fragment="right"> 这里是modules的right fragment </div> <div th:fragment="foot"> 这里是modules的foot fragment </div> </body> </html>
定义了四个模块,head,left,right,foot.
之后新建另一个main.html文件,在其中使用th:include="/目录/文件名::模块名"来引入这个模块,也有使用"~{目录/文件名::模块名}"来引入的.实测都可行
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" xmlns:layout="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>Main</title> </head> <body> <div> <p>这里是主页面</p> </div> <div id="head" th:include="/modules/mainModule::head">这里是主页面的头部,包含的modules的一个文件里的头模块</div> <div th:include="/modules/mainModule::left">这里是主页面的头部,包含的modules的一个文件里的左模块</div> <div th:include="/modules/mainModule::right">这里是主页面的头部,包含的modules的一个文件里的右模块</div> <div th:include="/modules/mainModule::foot">这里是主页面的头部,包含的modules的一个文件里的jio模块</div> </body> </html>
两个文件的目录结构如下:
在controller控制器中写一个main.html的接口
@RequestMapping("/main")
public ModelAndView main(){
ModelAndView modelAndView=new ModelAndView();
modelAndView.setViewName("/tempage/main");
return modelAndView;
}
启动项目,通过路径访问就可以看到刚刚写的页面
可以看到定义的4个DIV中显示的内容是我们在mainModule.html中定义的fragment的内容而不是main.html中的内容.
但是这种写法有个弊端,就是对于fragment模块无法进行动态的初始化,我之前试过写一个返回模块的接口,但是在include时依然只是单纯引入,不会调用接口,所以这种方法比较实适用于头,脚等规定模块的引入.
在刚才的main.html中定义两个button,同时为它们添加两个点击事件
<button id="switchHead" onclick="changeHead()">切换头部</button>
<button id="switchHead2" onclick="changeHead2()">再切一次</button>
script中添加函数
<script src="http://libs.baidu.com/jquery/1.8.3/jquery.min.js"></script> <script> function changeHead(){ $.ajax({ url:"/page/headModule", type:"post", // data:{"param":"2"}, // dataType:"json", success: function (data) { $("#head").html(data); } }); } function changeHead2(){ $.ajax({ url:"/page/leftModule", type:"post", // data:{"param":"2"}, // dataType:"json", success: function (data) { $("#head").html(data); } }); } </script>
其中这两个函数的url是controller中定义的返回head模块和left模块的接口
@RequestMapping("/headModule")
public ModelAndView headModule(){
ModelAndView modelAndView=new ModelAndView();
modelAndView.setViewName("/modules/mainModule::head");
return modelAndView;
}
@RequestMapping("/leftModule")
public ModelAndView leftModule(){
ModelAndView modelAndView=new ModelAndView();
modelAndView.setViewName("/modules/mainModule::left");
return modelAndView;
}
这里需要注意的是,springboot返回模块的方式是 “/目录/文件名::模块名”,这两个接口返回的就是我们刚刚在mainModule.html文件中定义的head和left.
这样,当我们在页面中点击两个按钮时,我们id为head的这个DIV就会被替换为接口返回的模块了.
录屏不好录,不展示了
适用layout:fragment可以实现动态切换layout部分的功能
首先在要被替换的部分创建一个DIV <div layout:fragment="content"></div>
,之后在其他文件中定义这个DIV的具体内容,可以理解为声明和重写吧~
举个栗子:
在刚才的main.html中定义一个DIV
<div layout:fragment="content">这里是分页模块</div>
在另一个文件page.html中重写这个DIV
<!DOCTYPE html> <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml" layout:decorator="tempage/main" xmlns:layout="http://www.w3.org/1999/xhtml"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div layout:fragment="content"> <p>这是fragment中的contentdiv</p> <button onclick="changePage()">点这里翻页!</button> <input type="text" id="pageNum"/> <div id="pageFragment" style="background-color: #00e765" th:fragment="pageFragment"> <div> <p>这是pageDiv里的Div,显示数据的</p> <ul th:each="pageDetail:${pageList.records}"> <li th:text="${pageDetail.title}">模板数据</li> </ul> </div> </div> </div> </body> </html>
在controller中添加这个文件的接口
@RequestMapping("/pageLayout") public ModelAndView pageLayout(HttpServletRequest request){ //获取参数 String pageStr=request.getParameter("page"); Integer page=1; if(Util.isNotEmpty(pageStr)){ page=Integer.parseInt(pageStr); } //查询数据 KjTalentActivityQuery query=new KjTalentActivityQuery(); query.setPage(page); query.setLimit(10); Page<KjTalentActivityEntity> activityPage=pageService.queryActivity(query); //封装页面 ModelAndView modelAndView=new ModelAndView(); modelAndView.setViewName("/fragment/page"); modelAndView.addObject("pageList",activityPage); return modelAndView; }
相当于这个页面的初始化,在调用这个接口时,根据参数查询数据库,得到返回值,封装为pageList属性,返回给页面,在页面中通过th:each遍历显示出来.
启动项目,当我们访问main时,显示的是div中默认的文字,如下图:
当我们更换路径,将路径换成刚才写的page的路径时,就会看到分页模块被替换成了page.html中的内容
当我们切换路径,比如传参数更换查询的页数时,绿色这个模块也会跟着改变.
这种方法的缺陷是,这种切换方式是全局刷新,如果其他地方我们做了样式变化,如果不使用参数进行限制,会被重置为默认状态.但是作为导航栏切换来说还算是很方便的
Layout解决了布局问题,th:fragment解决了局部刷新问题,两个联合在一起就可以解决我们被layout包含这个模块的异步刷新问题.
继续刚才的main.html和page.html
刚才的page.html中,我做了一个input框来输入页码,一个button来触发ajax分页异步刷新,显示数据的div定义为了一个th:fragment="pageFragment"
js部分代码如下:
<script src="http://libs.baidu.com/jquery/1.8.3/jquery.min.js"></script> <script> function changePage(){ var pageNum=$("#pageNum").val(); alert(pageNum); $.ajax({ url:"/page/pageModule", type:"post", data:{"page":pageNum}, dataType:"html", success: function (data) { console.log(data); $("#pageFragment").html(data); }, error:function(data){ console.log("error:+"+data); } }); } </script>
请求controller返回这个fragment的接口,通过ajax实现局部刷新
controller:
@RequestMapping("/pageModule") public ModelAndView pageModule(HttpServletRequest request){ //获取参数 String pageStr=request.getParameter("page"); Integer page=1; if(Util.isNotEmpty(pageStr)){ page=Integer.parseInt(pageStr); } //查询数据 KjTalentActivityQuery query=new KjTalentActivityQuery(); query.setPage(page); query.setLimit(10); Page<KjTalentActivityEntity> activityPage=pageService.queryActivity(query); //封装页面 ModelAndView modelAndView=new ModelAndView(); modelAndView.setViewName("/fragment/page::pageFragment"); modelAndView.addObject("pageList",activityPage); return modelAndView; }
这个接口返回的是一整个pageFragment,将这个fragment使用html()函数直接替换掉fragment所在的DIV就可以了
在network中可以看到这个ajax请求的返回值
通过success中的$("#pageFragment").html(data);
实现异步刷新.
录屏不好录,不录了.就是普通的ajax异步刷新效果!
能直接返回模块的好处是避免在ajax中拼接标签+数据,也避免在后台写,也算是标签的可复用吧hhhhhh
大概就是这个样子了.具体实际应用再遇到问题再来补充.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。