交换
响应的 HTML 拿到手,往哪里放、怎么放——由 hx-target 与 hx-swap 共同决定。「为什么只能替换整个页面?」 这一问,本章作答。
八种策略
hx-swap 的取值,本质是一组 DOM 插入位置加两个特殊指令:
| 值 | 语义 |
|---|---|
innerHTML | (默认)替换目标元素的内部内容 |
outerHTML | 连同目标元素自身一起替换 |
beforebegin | 插到目标之前 |
afterbegin | 插到目标内部的开头 |
beforeend | 插到目标内部的末尾 |
afterend | 插到目标之后 |
delete | 删除目标元素(响应被忽略) |
none | 什么都不换——只借请求触发副作用与事件 |
「替换整个页面」只是浏览器最早的默认值;在 htmx 的世界,替换粒度由你钦定。
修饰符
策略之后可缀以分号分隔的修饰符:
<div hx-swap="innerHTML swap:0.5s settle:1s scroll:top show:.app">…</div>
<!-- swap:0.5s 延迟 500ms 再换入(可让出场动画先跑完)
settle:1s 换入后延迟 1s 再添加 htmx-settling 类
scroll:top 换入后把目标滚动到顶部(可配滚动容器)
show:.app 换入后让目标在 .app 滚动容器内可见
transition:true 启用 CSS View Transitions -->延迟换入的妙用:请求返回后,先给「旧内容」留一段体面的退场时间,再瞬间换入新内容,观感上毫无等待——这是 htmx 官方教程中著名的 swap: 技巧。
过渡动画
htmx 用三个 CSS 类把生命周期暴露给样式表,过渡信手拈来:
| 类 | 何时出现 |
|---|---|
.htmx-request | 请求进行中(挂在触发元素与 hx-indicator 指定的元素上) |
.htmx-swapping | 旧内容即将移除时(配合 transition CSS 做退场) |
.htmx-settling | 换入之后、结构稳定前的瞬间(做入场补间) |
.htmx-swapping { opacity: 0; transition: opacity .25s ease-out; }
.htmx-settling { background: var(--cinnabar-wash); transition: background 1s ease; }若旧内容的退场动画没跑完就被替换,多半是忘了
swap: 延迟——给动画让路,再换。旁路交换(Out of Band Swaps)
一次请求,多处落点:响应里给「捎带更新」的片段标上 hx-swap-oob,主目标照常换,旁路各归各家:
<!-- 主内容:删除的行换成空 -->
<tr id="row-7"></tr>
<!-- 旁路:顺手刷新角标计数 -->
<span id="cart-count" hx-swap-oob="true">3 件</span>
<!-- 旁路还能自带策略 -->
<aside id="toast" hx-swap-oob="afterend">已删去第 7 行</aside>发起端只需处理主目标即可;多个旁路时配合 hx-select-oob 精确点名。
交换实验室
下面的演示直接打本站服务器——每一枚时间戳卡片,都是一次真实 HTTP 往返生成的 HTML:
这里还空着——点上面的按钮,让服务器生成 HTML 换进来。
下拉框经
hx-on:change 实时改写按钮的 hx-swap——换成 beforeend 再点「生成一枚时间戳」,新卡片便层层叠上;「追加」按钮则固定用 beforeend 只加在末尾。这就是只换一角与刷新整页的区别。