htmx

目标元素与内容交换策略

By AI-Writer 6 min read

目标元素与内容交换策略

发起请求只是第一步,更重要的是响应内容如何、在哪里被插入页面。htmx 通过 hx-targethx-swap 两个核心属性,提供了极其灵活的内容更新控制机制。本文将深入讲解这两个属性的所有用法。

hx-target:指定更新目标

hx-target 决定服务器返回的 HTML 应该更新哪个元素。如果未指定,默认更新触发请求的元素本身。

CSS 选择器

最直接的方式是使用 CSS 选择器:

html
<button hx-get="/api/notification-count" hx-target="#badge">
    刷新通知
</button>
<span id="badge">0</span>

支持任意有效的 CSS 选择器:

html
<!-- ID 选择器 -->
<div hx-get="/content" hx-target="#main"></div>

<!-- 类选择器 -->
<div hx-get="/content" hx-target=".sidebar"></div>

<!-- 属性选择器 -->
<div hx-get="/content" hx-target="[data-region='header']"></div>

<!-- 组合选择器 -->
<div hx-get="/content" hx-target="#list > li:first-child"></div>

特殊关键字

htmx 提供了几个便利的关键字,避免编写复杂的选择器:

关键字含义示例
this触发请求的元素本身hx-target="this"
closest <selector>最近的匹配祖先元素hx-target="closest tr"
find <selector>在元素内部查找匹配子元素hx-target="find .result"
next紧邻的下一个兄弟元素hx-target="next"
previous紧邻的上一个兄弟元素hx-target="previous"

this:更新自身

html
<button hx-get="/api/toggle/123"
        hx-target="this"
        hx-swap="outerHTML">
    启用
</button>

点击后按钮本身被服务器返回的新 HTML 替换(可能变为”禁用”状态)。

closest:更新最近祖先

html
<ul>
    <li>
        任务一
        <button hx-delete="/api/tasks/1"
                hx-target="closest li"
                hx-swap="delete">
            删除
        </button>
    </li>
</ul>

closest li 找到按钮所在的最近的 <li> 元素。hx-swap="delete" 会删除该元素,无需服务器返回内容。

提示closest 在处理列表项操作时特别有用。每个删除按钮都可以使用相同的 hx-target="closest li",不需要为每个项设置唯一 ID。

find:在内部查找

html
<div hx-get="/api/dashboard" hx-target="find .metrics">
    <div class="metrics">加载中...</div>
</div>

find .metrics 在当前元素内部查找 .metrics 子元素进行更新,而不是更新整个容器。

next / previous:兄弟元素

html
<button hx-get="/api/details" hx-target="next">
    展开详情
</button>
<div class="details" style="display:none;"></div>

next 选中紧邻的下一个兄弟元素,非常适合展开/折叠场景。

html
<div class="preview">内容预览</div>
<button hx-get="/api/full" hx-target="previous">
    查看完整内容
</button>

hx-swap:控制交换策略

hx-swap 定义了响应内容如何插入到目标元素中。默认策略是 innerHTML(替换目标元素的内部内容)。

八种交换策略

策略行为描述示例场景
innerHTML替换目标元素的内部 HTML(默认)更新内容区域
outerHTML替换目标元素本身替换列表项
beforebegin在目标元素之前插入(同级)在列表前添加项
afterbegin在目标元素内部的开始处插入在列表顶部添加
beforeend在目标元素内部的末尾处插入在列表底部添加
afterend在目标元素之后插入(同级)在元素后插入新元素
delete删除目标元素,忽略响应删除操作
none不插入任何内容仅触发事件

innerHTML(默认)

html
<div id="content" hx-get="/api/page/2">
    第一页内容
</div>

请求返回的 HTML 替换 #content内部内容,<div id="content"> 标签本身保留。

outerHTML

html
<div id="item-1" hx-get="/api/item/1/edit" hx-swap="outerHTML">
    <span>任务 1</span>
    <button>编辑</button>
</div>

返回的 HTML 替换整个 #item-1 元素。常用于将只读视图替换为编辑表单,或反之。

四种 sibling 插入策略

假设有以下结构:

html
<div id="container">
    <p>现有内容</p>
</div>

服务器返回:<p>新内容</p>

策略结果
beforebegin<p>新内容</p><div id="container">...</div>
afterbegin<div id="container"><p>新内容</p><p>现有内容</p></div>
beforeend<div id="container"><p>现有内容</p><p>新内容</p></div>
afterend<div id="container">...</div><p>新内容</p>

beforeend:无限滚动列表

html
<ul id="items" hx-get="/api/more" hx-trigger="revealed" hx-swap="beforeend">
    <li>项目 1</li>
    <li>项目 2</li>
</ul>

当列表滚动到视口时(revealed 触发器),加载更多项目并追加到列表末尾。

delete:删除操作

html
<button hx-delete="/api/items/42"
        hx-target="closest .card"
        hx-swap="delete"
        hx-confirm="确定删除?">
    🗑️
</button>

hx-swap="delete" 直接删除目标元素(最近的 .card),不需要服务器返回任何内容。

none:纯事件触发

html
<button hx-post="/api/track"
        hx-swap="none"
        hx-on::after-request="alert('记录已保存')">
    记录点击
</button>

hx-swap="none" 表示不更新任何 DOM,只执行事件处理。适合日志记录、分析统计等场景。

hx-select:选择部分内容

有时服务器返回的 HTML 包含完整页面,但你只需要其中一部分。hx-select 可以从响应中提取指定内容。

基础用法

html
<div hx-get="/full-page" hx-select="#sidebar-content" hx-target="#sidebar">
    刷新侧边栏
</div>

服务器返回完整 HTML 页面,但 htmx 只提取其中 #sidebar-content 的内容插入到页面的 #sidebar 中。

排除内容

结合 :not() 排除不需要的部分:

html
<div hx-get="/article/123"
     hx-select=".content:not(.ads)"
     hx-target="#reader">
    加载文章
</div>

高级交换修饰符

hx-swap 支持多个修饰符,进一步控制交换行为:

过渡修饰符

修饰符说明
swap:N内容移除与新内容插入之间的延迟(毫秒)
settle:N新内容插入后 CSS 过渡的完成时间(毫秒)
html
<div hx-get="/api/update"
     hx-swap="innerHTML swap:100ms settle:300ms">
    更新
</div>

swap:100ms 表示旧内容移除和新内容插入之间有 100ms 间隔,让你有时间添加过渡动画。

滚动修饰符

修饰符说明
scroll:top交换后滚动到目标元素顶部
scroll:bottom交换后滚动到目标元素底部
show:top交换后确保目标元素顶部在视口内
show:bottom交换后确保目标元素底部在视口内
html
<div hx-get="/api/messages"
     hx-target="#chat"
     hx-swap="beforeend scroll:bottom">
    加载新消息
</div>

新消息追加到聊天区域后,自动滚动到底部。

html
<form hx-post="/api/comments"
      hx-target="#comments"
      hx-swap="beforeend show:bottom">
    <!-- 发表评论后,确保最新评论可见 -->
</form>

聚焦修饰符

修饰符说明
focus-scroll:true / focus-scroll:false交换后是否保持焦点元素的滚动位置
html
<div hx-get="/api/live-data"
     hx-trigger="every 5s"
     hx-swap="innerHTML focus-scroll:false">
    <!-- 定时刷新,但不因为焦点变化而滚动页面 -->
</div>

完整交换配置示例

html
<div id="feed"
     hx-get="/api/posts"
     hx-trigger="revealed"
     hx-target="#feed"
     hx-swap="beforeend swap:50ms settle:200ms show:bottom"
     hx-select=".post-item"
     hx-indicator=".loading">
    <article class="post-item">...</article>
</div>

<div class="loading htmx-indicator">加载更多...</div>

这个配置实现了完整的无限滚动体验:

  • hx-trigger="revealed" — 元素进入视口时触发
  • hx-swap="beforeend" — 新内容追加到末尾
  • swap:50ms settle:200ms — 提供动画过渡时间窗口
  • show:bottom — 保持滚动位置合理
  • hx-select=".post-item" — 只提取文章条目
  • hx-indicator — 显示加载状态

完整示例:待办事项列表

html
<ul id="todo-list">
    <li>
        <span>学习 htmx</span>
        <button hx-delete="/api/todos/1"
                hx-target="closest li"
                hx-swap="delete"
                hx-confirm="确定完成并删除?">
            完成
        </button>
    </li>
</ul>

<form hx-post="/api/todos"
      hx-target="#todo-list"
      hx-swap="beforeend"
      hx-on::after-request="this.reset()">
    <input type="text" name="text" placeholder="新任务..." required />
    <button type="submit">添加</button>
</form>
交互目标交换策略效果
添加任务#todo-listbeforeend追加到列表末尾
完成任务closest lidelete删除该行

总结

hx-targethx-swap 是 htmx 中最强大的属性组合,掌握它们意味着你可以精确控制页面更新的每一个细节:

  • hx-target — 支持 CSS 选择器和 this/closest/find/next/previous 关键字,灵活定位更新目标
  • hx-swap — 8 种交换策略覆盖所有插入场景,配合修饰符实现过渡动画和滚动控制
  • hx-select — 从响应中提取部分内容,适配非专门为 htmx 设计的后端接口

下一篇文章将深入探讨 触发器与修饰符,理解 hx-trigger 如何精确控制请求的时机和条件。

#htmx #hx-target #hx-swap #dom

评论

A

Written by

AI-Writer

Related Articles

htmx
#1

htmx 简介与核心概念

理解 htmx 的设计哲学与核心机制,学习如何通过 HTML 属性实现 AJAX 交互,无需编写 JavaScript 即可构建动态网页

Read More
htmx
#10

CSS 过渡与动画

学习利用 htmx 的 swap/settle 修饰符与 CSS 过渡实现平滑的界面变化,掌握常用的淡入、滑入、缩放等动画模式

Read More
htmx
#9

与后端框架集成

学习 htmx 与 Django、Flask、FastAPI、Laravel 等主流后端框架的配合模式,掌握 HX-Request 头识别、模板片段组织等核心集成技巧

Read More