---
url: /htmx/introduction.md
description: >-
  htmx是什么？2026年8月28日刚发布4.0.0的轻量级前端库，用HTML属性就能发AJAX/WebSocket请求，十几KB干掉React全家桶，官方真实案例代码量直降67%、JS依赖从255个砍到9个，五分钟搞懂HTML
  over the wire
---

# 认识htmx

你有没有算过，为了做一个"点击加载更多"的按钮，你的项目里塞了多少东西？

`npm install` 敲下去，`node_modules` 300MB，`package-lock.json` 一万行。你写了个 `<button>`，然后配了 React、配了路由、配了状态管理、配了请求库、配了构建工具。等终于跑起来，首屏 2 秒可交互——你还得安慰自己"现代前端就该这样"。

然后有个法国公司做了件很不给面子的事：他们把**做了两年**的 React UI 换成 Django 模板 + htmx，**两个月**搞定，代码从 **21500 行砍到 7200 行**，JS 依赖从 **255 个砍到 9 个**，构建时间从 **40 秒降到 5 秒**。用户体验？没变差。

这家公司叫 Contexte，这个分享后来被 htmx 官方称为"**所有 htmx Demo 之母**"。

> 前端这十年最大的幻觉是：交互一定要在浏览器里做。而大部分后台系统，其实只是"表单 + 表格 + 看板"。

2026 年 8 月 28 日——就在昨天——**htmx 4.0.0 正式发布**，8 个月打磨，登上 Hacker News 首页。它干的第一件事就挺反常识：**拒不把自己标成 npm 的 `latest`**。

## 什么是 htmx

htmx 是一个只有十几 KB（官方主页口径约 16KB min.gz）的 JavaScript 库，零依赖，无构建步骤。它的全部主张可以用一句话说完：

**让任意 HTML 元素都能发 HTTP 请求，让服务器直接返回 HTML 片段，浏览器负责把它换进去。**

不用写 JSON API，不用在客户端维护第二份状态，不用虚拟 DOM。你在 HTML 里加几个属性就完事：

```html
<button hx-post="/clicked" hx-swap="outerHTML">
  点我
</button>
```

这行代码的意思是：点这个按钮 → 向 `/clicked` 发一个 POST → 用服务端返回的 HTML 把按钮自己替换掉。逻辑、状态、渲染全在服务端，浏览器只做"换"这一个动作。

> 凭什么只有 `<a>` 和 `<form>` 能发请求？凭什么只有 click 和 submit 能触发？凭什么每次都得整页刷新？——htmx 的四个"凭什么"

htmx 出自 Carson Gross 之手，是 intercooler.js 的继任者，BSD 2-Clause 协议开源，目前在 GitHub 上接近 **4.9 万 Star**。它的理论根基是 Roy Fielding 原始意义上的 REST 与 HATEOAS——**服务端不只返回数据，还把"下一步能干什么"一起写在 HTML 里**。

配套的还有个好玩的说法叫 **HOWL 技术栈**（Hypermedia On Whatever you'd Like）：因为服务端只需要吐 HTML，你用 Django、Flask、FastAPI、Rails、Laravel、Go、Express 都行，htmx 根本不挑。

## htmx 4.0 到底更新了什么

先说结论：**从使用者视角看，htmx 4 和 htmx 2 几乎一样**。官方明确说了，两者行为差异很小，而且**htmx 2.x 会无限期维护，你完全不用急着升**。

### 底层：XMLHttpRequest 换成了 fetch()

这是整个版本的地基。XHR 是 IE 时代的老古董，有个硬伤：**必须把整个响应缓冲完，htmx 才能往 DOM 里塞**。换成 `fetch()` 之后有了 `ReadableStream`，HTML 就能边到边渲染——真正的流式 UI，而且只靠一个十几 KB 的库。

代价是：你在 2.x 里写过 XHR 拦截器、自定义传输层的话，会挂。`htmx:xhr:*` 系列事件也全部移除。

### 三大破坏性变化

* **属性继承变成显式的（这是最大的升级负担）**。htmx 2 里父元素的 `hx-target`、`hx-confirm` 会自动被子元素继承，灵感来自 CSS——然后也和 CSS 一样,强大但难懂。htmx 4 里必须显式加 `:inherited`：

  ```html
  <!-- htmx 2 -->
  <div hx-confirm="确定删除？">
      <button hx-delete="/item/1">删除</button>
  </div>

  <!-- htmx 4 -->
  <div hx-confirm:inherited="确定删除？">
      <button hx-delete="/item/1">删除</button>
  </div>
  ```

  坑在哪？**它不报错**。忘了加，按钮就静悄悄地不再弹确认框、不再指向正确的目标。所以官方专门给了命令行检查工具（见下文）。

* **事件名标准化**为 `htmx:phase:action[:sub-action]`。`htmx:beforeRequest` → `htmx:before:request`，`htmx:configRequest` → `htmx:config:request`。大部分错误事件合并进 `htmx:error`，HTTP 错误统一走 `htmx:response:error`。

* **history 不再用 `localStorage` 缓存快照**。2.x 把整页 DOM 快照存 localStorage，结果第三方 JS 改过的 DOM 会被一起存进去，恢复时 DOM 回来了、JS 逻辑没了——一堆玄学 bug。htmx 4 改成后退时**重新拉取页面**，配合 HTTP 缓存又快又正确。

### 两个真正的新玩具

**Morph 交换进核心了。** idiomorph（Carson 自己写的 DOM 合并算法）原本是 2.x 的扩展，现在内置。新的 swap 样式是 `innerMorph` / `outerMorph`：不再粗暴地整块替换，而是把新内容**合并**进现有 DOM。输入框焦点不跳、视频不中断、CSS 过渡不断。这不就是 React 那套 diff，但没有 React。

```html
<div hx-get="/dashboard" hx-swap="innerMorph" hx-trigger="every 5s">
  <!-- 看板内容，5 秒刷新一次，但你不觉得它在刷新 -->
</div>
```

**`<hx-partial>` 标签。** 想在一次响应里更新多个元素？2.x 的 OOB（out-of-band）交换能把人绕晕。htmx 4 直接给你一个能自己声明目标和策略的标签：

```html
<hx-partial hx-target="#messages" hx-swap="beforeend">
    <div>新消息</div>
</hx-partial>
<hx-partial hx-target="#count">
    <span>5</span>
</hx-partial>
```

意图写在 HTML 结构里，一眼能看懂，比满屏属性汤舒服太多。

### 扩展生态：fetch() 带来的连锁反应

换成 `fetch()` 之后，扩展的可能性一下打开了，这次一口气放出一批：

* `hx-preload`：鼠标悬停就预加载，点击时请求已经在路上了
* `hx-download`：基于 fetch 的原生文件下载，不用再玩 iframe 黑魔法
* `hx-sse` / `hx-ws` / `hx-multipart`：三种流式传输（SSE、WebSocket、multipart/mixed）
* `hx-alpine-compat` / `hx-history-cache`：和 Alpine.js 的配合与历史缓存
* `hx-live`：htmx 团队自己下场做的前端脚本方案，受 Alpine、jQuery、hyperscript 启发，主打"DOM 驱动的、HATEOAS 友好的响应式"
* `htmax.js`：懒得挑？一个文件打包 htmx + 常用扩展，直接用

另外还有个值得注意的默认行为变化：**htmx 4 默认会交换 4xx/5xx 响应**（2.x 会直接忽略）。服务端返回 422 + 一段校验错误的 HTML，它会老老实实换进目标里——用户终于能看到反馈了。想精确控制就用新的 `hx-status`：

```html
<form hx-post="/save"
      hx-status:422="swap:innerHTML target:#errors select:#validation-errors"
      hx-status:5xx="swap:none push:false">
```

还有个容易踩的：默认超时从"永不超时"改成了 **60 秒**。

## 谁在用：真实案例，带硬数据

说架构都是虚的，上真数据。

**Contexte（法国政策与政治媒体 SaaS）**——这是最完整、最经得起查的一个案例，2022 年 DjangoCon Europe 上由 David Guillot 公开分享，被 htmx 官方收录：

* 迁移耗时 **2 个月**（原代码库 21500 行，绝大部分是 JS）
* 代码总量 **减少 67%**（21500 → 7200 行）
* **Python 代码增加 140%**（500 → 1200 行）——在官方看来这是好事，能用 Python 就别用 JS
* JS 依赖 **减少 96%**（255 个 → 9 个）
* 构建时间 **减少 88%**（40 秒 → 5 秒）
* 首屏可交互时间 **降低 50~60%**（2~6 秒 → 1~2 秒）
* 内存占用 **降低 46%**（75MB → 45MB）
* 数据集容量反而变大了——原来 React 根本扛不住那个数据量

还有一个容易被忽略的收益：**团队结构变了**。用 React 时，2 个纯后端、1 个纯前端、1 个"全栈"；换成 htmx 后，**4 个人全成了全栈**。每个人都能独立交付一个完整功能，不用跨端协调。

> 一个后台页面的成本，从来不只是代码行数，还有"改一个字段要三个人排期"这件事。

除此之外，社区侧的体感数据也值得一提：`awesome-htmx` 资源库 **2200+ Star** 还在涨，npm 上月下载量在**六十万级**。当然，实话实说，htmx 目前的主力战场仍然是**内部工具、管理后台、CRUD、内容型应用**——你要做在线表格、实时地图、离线优先的应用，老老实实用 React，别硬来。

## 初体验：五分钟跑起来

**第一步：引一行脚本。** 注意版本号必须写死 4.0.0——因为 npm 上 `latest` 还指向 2.x，官方要等到 **2027 年初**才切。这个"不催你升级"的态度，在一个天天催你升大版本的前端圈子里，算一股清流。

```html
<script src="https://unpkg.com/htmx.org@4.0.0/dist/htmx.min.js"></script>
```

**第二步：配个 Python 后端。** 站内已经有 Flask 的文章，这里就用 Flask 搭一个"边打字边搜"的列表，全文法加起来不到 30 行：

```python
# pip install flask
from flask import Flask, render_template_string, request

app = Flask(__name__)

DATA = ["Doris", "DuckDB", "SeaTunnel", "StarRocks", "Paimon", "TiDB", "ClickHouse"]

PAGE = """
<script src="https://unpkg.com/htmx.org@4.0.0/dist/htmx.min.js"></script>
<input type="search" name="q"
       hx-get="/search"
       hx-trigger="keyup changed delay:300ms"
       hx-target="#result"
       placeholder="搜一个开源项目">
<div id="result">{% for r in rows %}<div>{{ r }}</div>{% endfor %}</div>
"""

ROWS = "{% for r in rows %}<div>{{ r }}</div>{% endfor %}"

@app.get("/")
def index():
    return render_template_string(PAGE, rows=DATA)

@app.get("/search")
def search():
    q = request.args.get("q", "").lower()
    return render_template_string(ROWS, rows=[d for d in DATA if q in d.lower()])

app.run(debug=True)
```

跑起来打字试试。没有 `fetch()`，没有 JSON，没有 `setState`，没有状态同步 bug——`delay:300ms` 还是 htmx 自带的防抖。

**第三步：如果你是从 htmx 2 升级的，先跑官方检查工具：**

```bash
npx htmx.org@4.0.0 upgrade-check -- ./templates
```

它会扫 `.html/.php/.js/.ts/.jinja/.jinja2/.j2/.erb/.hbs`，把继承缺失、属性改名/移除、旧事件名、废弃 API 全给你点出来，连"这个 CSRF header 忘了加 `:inherited`，服务端会拒绝请求"这种都提示到了。官方甚至还放了四个 **LLM skills 文件**（`htmx-guidance`、`htmx-debugging`、`htmx-extension-authoring`、`htmx-upgrade-from-htmx2`），给 AI 编程助手喂正确上下文——这大概是前端库里第一个这么干的。

> 入门别贪多：先挑一个你项目里"没必要上 React"的小角落——搜索框、加载更多、表单提交后刷新一个面板——用几个 `hx-` 属性重写一遍。一下午就能验证合不合适，比开一场架构评审会划算得多。

## 进阶

更多开源技术干货和学习资料，关注公众号「遇码」，领取专属福利。
