Skip to content

8.3 灵活的布局:超越单纯的片段插入

借助片段表达式的强大能力,我们可以给模板片段传递「非文本/数字/对象类型」的参数——具体来说,是传递标记片段(markup fragments)

这种方式能让我们设计出可被「动态增强」的通用片段:调用模板可以传入自定义的标记内容,片段会将这些内容融合到自身结构中,最终实现高度灵活的模板布局机制。

注意看下面这个片段,它接收 titlelinks 两个参数(类型为标记片段),并将其嵌入到自身结构中:

html
<!-- base.html 中的通用头部片段 -->
<head th:fragment="common_header(title,links)">
  <!-- 替换为传入的 title 标记片段 -->
  <title th:replace="${title}">The awesome application</title>

  <!-- 通用样式/脚本(所有页面共享) -->
  <link rel="stylesheet" type="text/css" media="all" th:href="@{/css/awesomeapp.css}">
  <link rel="shortcut icon" th:href="@{/images/favicon.ico}">
  <script type="text/javascript" th:src="@{/sh/scripts/codebase.js}"></script>

  <!-- 每页自定义链接的占位符:替换为传入的 links 标记片段 -->
  <th:block th:replace="${links}" />
</head>

在业务页面中调用 common_header,并传入当前页面的 <title><link> 作为标记片段参数:

html
<!-- 业务页面的头部:调用通用片段并传递自定义标记 -->
<head th:replace="~{ base :: common_header(~{::title},~{::link}) }">
  <!-- 自定义标题:会作为 title 参数传入片段 -->
  <title>Awesome - Main</title>

  <!-- 自定义样式链接:会作为 links 参数传入片段 -->
  <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}">
  <link rel="stylesheet" th:href="@{/themes/smoothness/jquery-ui.css}">
</head>
  • ~{::title}:选取当前模板中 <title> 标签的标记片段,作为 title 参数;
  • ~{::link}:选取当前模板中所有 <link> 标签的标记片段,作为 links 参数;
  • 调用时将这两个标记片段传递给 common_header,实现通用片段的动态定制。

通用片段会融合传入的自定义标记,生成既包含通用内容、又有页面自定义内容的头部:

html
<head>
  <!-- 来自调用模板的自定义标题 -->
  <title>Awesome - Main</title>

  <!-- 通用样式/脚本(片段自带) -->
  <link rel="stylesheet" type="text/css" media="all" href="/awe/css/awesomeapp.css">
  <link rel="shortcut icon" href="/awe/images/favicon.ico">
  <script type="text/javascript" src="/awe/sh/scripts/codebase.js"></script>

  <!-- 来自调用模板的自定义样式链接 -->
  <link rel="stylesheet" href="/awe/css/bootstrap.min.css">
  <link rel="stylesheet" href="/awe/themes/smoothness/jquery-ui.css">
</head>

核心优势与扩展说明

  1. 布局复用+个性化:通用片段保留所有页面的公共内容(如基础样式、脚本),同时通过标记参数接收页面自定义内容,兼顾复用性和灵活性;
  2. th:block 的价值:用于承载「无实体标签的替换逻辑」,避免生成多余的 <div>/<span> 等标签,保持 HTML 结构简洁;
  3. 更灵活的传参方式:可传递任意标记片段(如 <script><meta> 等),甚至是带条件判断的动态标记:
    html
    <!-- 传入带条件的自定义脚本片段 -->
    <head th:replace="~{ base :: common_header(
      ~{::title},
      ~{::link},
      ~{<th:block th:if="${user.isAdmin}"><script th:src="@{/js/admin.js}"></script></th:block>}
    ) }">
      ...
    </head>
  4. 简化写法:可省略片段表达式的 ~{},简写为:
    html
    <head th:replace="base :: common_header(::title,::link)">
      ...
    </head>

总结

  1. 片段表达式支持传递「标记片段」作为参数,让通用片段可接收调用模板的自定义标记;
  2. 核心思路是「通用结构+自定义内容」:通用片段封装公共布局,调用模板传入页面专属标记;
  3. th:block 是实现无冗余布局的关键,可承载标记替换逻辑而不生成额外标签。