深色模式
10 属性优先级
当你在同一个标签中写多个 th:* 属性时,会发生什么, 比如这个遍历+文本渲染的例子:
html
<li th:each="item : ${items}" th:text="${item.description}">Item description here...</li>我们需要 th:each 先执行(遍历生成每个 <li>),再执行 th:text(渲染当前 item 的描述),这才是我们想要的结果。HTML/XML 标准本身不对属性顺序赋予任何语义,也不会按属性在标签中的书写顺序执行,所以必须通过优先级机制保证逻辑执行的正确性。
所以,Thymeleaf 遵循内置的属性优先级规则:
| 优先级顺序 | 功能分类 | 对应属性 |
|---|---|---|
| 1 | 片段引入 | th:insert、th:replace |
| 2 | 片段遍历 | th:each |
| 3 | 条件判断 | th:if、th:unless、th:switch、th:case |
| 4 | 局部变量定义 | th:object、th:with |
| 5 | 通用属性修改 | th:attr、th:attrprepend、th:attrappend |
| 6 | 特定属性修改 | th:value、th:href、th:src(所有针对单个 HTML 属性的 th:* 都属于此类) |
| 7 | 文本/标签体修改 | th:text、th:utext |
| 8 | 片段声明 | th:fragment |
| 9 | 片段移除 | th:remove |
这就是属性优先级的作用:无论书写顺序如何,优先级高的属性先执行。(顺序调换,会导致可读性不高)
html
<!-- 顺序调换,但执行逻辑不变 -->
<li th:text="${item.description}" th:each="item : ${items}">Item description here...</li>优先级规则的实际应用示例
示例1:遍历 + 条件判断 + 文本渲染
html
<!-- 执行顺序:th:each(2)→ th:if(3)→ th:text(7) -->
<li th:each="item : ${items}"
th:if="${item.active}"
th:text="${item.name}">Item name</li>逻辑解析:
- 先执行
th:each遍历items,生成每个 item 对应的<li>; - 再执行
th:if判断当前 item 是否激活,未激活则跳过; - 最后执行
th:text渲染激活 item 的名称。
示例2:局部变量 + 链接生成
html
<!-- 执行顺序:th:with(4)→ th:href(6) -->
<a th:with="prodId=${product.id}"
th:href="@{/product/detail(id=${prodId})}">View Detail</a>逻辑解析:
- 先执行
th:with定义局部变量prodId; - 再执行
th:href利用prodId生成链接(若反过来写,结果也不变)。
示例3:片段引入 + 条件移除
html
<!-- 执行顺序:th:insert(1)→ th:remove(9) -->
<div th:insert="common :: adminBar"
th:remove="${!user.isAdmin}? all : none">Admin Bar</div>逻辑解析:
- 先执行
th:insert引入管理员栏片段; - 再执行
th:remove判断是否移除(非管理员则移除整个 div)。
关键注意事项
- 优先级高于书写顺序:无论属性在标签中写在前面还是后面,都严格按优先级执行(比如
th:text永远在th:each之后执行); - 可读性建议:虽然顺序不影响执行,但建议按“高优先级→低优先级”的顺序书写属性(如先
th:each再th:text),提升代码可读性; - 同优先级属性:同一优先级的属性(如
th:if和th:unless)会按书写顺序执行,但通常不建议在同一标签中写同优先级的互斥属性(如同时写th:if和th:unless)。
总结
- Thymeleaf 通过属性优先级解决多属性的执行顺序问题,与书写顺序无关;
- 核心优先级逻辑:片段引入 > 遍历 > 条件判断 > 变量定义 > 属性修改 > 文本渲染 > 片段声明 > 移除;
- 书写时建议按优先级顺序排列属性,兼顾执行正确性和代码可读性。
