一个博客有二十来个页面,每个页面顶部都要放导航、底部都要放页脚。复制粘贴的后果是:
新建 templates/fragments/site-footer.html:
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.w3.org/1999/xhtml">
<body>
<footer th:fragment="site-footer" class="ui inverted vertical segment">
<div class="ui container">
<p>© 2020-2026 一颗星的博客</p>
<p>
<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener nofollow">
蜀ICP备2021032163号-2
</a>
</p>
</div>
</footer>
</body>
</html>
页面里引用:
<div th:replace="~{fragments/site-footer :: site-footer}"></div>
以后改备案号,只动这一个文件。
导航需要在不同页面高亮不同的菜单项,片段就要带参数:
<nav th:fragment="site-nav(active, hidden)" class="gird-header"
th:id="${hidden} ? 'nav' : null"
th:style="${hidden} ? 'display:none' : null">
<a th:href="@{/}" th:classappend="${active == 'index'} ? 'active'">首页</a>
<a th:href="@{/archives}" th:classappend="${active == 'archives'} ? 'active'">时间轴</a>
</nav>
调用:
<nav th:replace="~{fragments/site-nav :: site-nav(active='index', hidden=false)}"></nav>
th:id="${hidden} ? 'nav' : null" 这个写法很实用:表达式返回 null 时,Thymeleaf 会把这个属性整个去掉,而不是渲染成 id="null"。
片段文件里也要写 xmlns:th,否则编辑器不认 th:* 属性。
片段路径是相对 参数名和片段签名必须对上, 把页脚抽出来之后,还发现一个隐性收益:所有页面的版权年份、备案号、联系方式天然一致。以前是"记得改",现在是"改一次全都对"。 这类"容易忘、忘了要出事"的内容,都应该收敛到一处。th:replace 会替换掉整个宿主标签,th:insert 才是插到标签内部。前者适合 里塞内容。
templates/ 的,写 fragments/site-footer 而不是 templates/fragments/site-footer。site-nav(active, hidden) 调用时少传一个,Spring 会报 TemplateProcessingException,而且错误信息不太直观,容易找半天。顺手解决的事