htmx
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseHTMX Skill
HTMX 使用指南
Provides guidance for building dynamic, interactive web applications using htmx - a library that enables modern browser features directly from HTML attributes.
本文提供使用htmx构建动态交互式Web应用的指南——htmx是一个可直接通过HTML属性启用现代浏览器功能的库。
Overview
概述
htmx extends HTML with attributes that allow any element to issue HTTP requests and update page content without writing JavaScript. It brings the power of AJAX, CSS Transitions, WebSockets, and Server-Sent Events directly into HTML markup.
Core Philosophy: Server returns HTML (not JSON), keeping you in the hypermedia/HATEOAS model. Any element can issue requests, not just anchors and forms. Any event can trigger requests, not just clicks and submissions.
htmx 通过扩展HTML属性,允许任何元素在无需编写JavaScript的情况下发送HTTP请求并更新页面内容。它将AJAX、CSS过渡、WebSockets和服务器发送事件的能力直接融入HTML标记中。
核心理念:服务器返回HTML(而非JSON),让你始终处于超媒体/HATEOAS模型中。任何元素都可以发送请求,而不仅仅是锚点和表单。任何事件都可以触发请求,而不仅仅是点击和提交操作。
Core Concepts
核心概念
AJAX Attributes
AJAX属性
Use these attributes to issue HTTP requests:
- - Issues GET request
hx-get="/url" - - Issues POST request
hx-post="/url" - - Issues PUT request
hx-put="/url" - - Issues PATCH request
hx-patch="/url" - - Issues DELETE request
hx-delete="/url"
html
<button hx-post="/clicked" hx-target="#result">
Click Me!
</button>
<div id="result"></div>使用以下属性发送HTTP请求:
- - 发送GET请求
hx-get="/url" - - 发送POST请求
hx-post="/url" - - 发送PUT请求
hx-put="/url" - - 发送PATCH请求
hx-patch="/url" - - 发送DELETE请求
hx-delete="/url"
html
<button hx-post="/clicked" hx-target="#result">
Click Me!
</button>
<div id="result"></div>Triggering Requests
触发请求
Control when requests fire with :
hx-triggerDefault triggers: use , uses , everything else uses
input/textarea/selectchangeformsubmitclickCustom triggers:
html
<!-- Trigger on mouseenter -->
<div hx-get="/data" hx-trigger="mouseenter">Hover me</div>
<!-- Trigger on keyup with delay -->
<input hx-get="/search" hx-trigger="keyup changed delay:500ms">
<!-- Multiple triggers -->
<div hx-get="/data" hx-trigger="mouseenter, focus">Modifiers:
- - Only trigger once
once - - Only if value changed
changed - - Wait before issuing request
delay:500ms - - Rate limit requests
throttle:1s - - Listen on different element
from:<selector>
Filters:
html
<!-- Only trigger if Ctrl key pressed -->
<div hx-get="/clicked" hx-trigger="click[ctrlKey]">Ctrl+Click</div>Special events:
- - Fires when element loads
load - - Fires when scrolled into viewport
revealed - - Poll every 2 seconds
every 2s
使用控制请求何时触发:
hx-trigger默认触发条件:使用事件,使用事件,其他所有元素使用事件
input/textarea/selectchangeformsubmitclick自定义触发条件:
html
<!-- 鼠标悬停时触发 -->
<div hx-get="/data" hx-trigger="mouseenter">Hover me</div>
<!-- 按键抬起并延迟触发 -->
<input hx-get="/search" hx-trigger="keyup changed delay:500ms">
<!-- 多个触发条件 -->
<div hx-get="/data" hx-trigger="mouseenter, focus">修饰符:
- - 仅触发一次
once - - 仅当值发生变化时触发
changed - - 延迟后发送请求
delay:500ms - - 限制请求频率
throttle:1s - - 监听不同元素的事件
from:<selector>
过滤器:
html
<!-- 仅当按下Ctrl键时触发 -->
<div hx-get="/clicked" hx-trigger="click[ctrlKey]">Ctrl+Click</div>特殊事件:
- - 元素加载时触发
load - - 元素滚动到视口中时触发
revealed - - 每2秒轮询一次
every 2s
Targeting and Swapping
目标与内容交换
Control where and how content is inserted:
Target selection with :
hx-targethtml
<button hx-get="/data" hx-target="#result">Load</button>
<div id="result"></div>Extended selectors:
- - The element itself
this - - Nearest ancestor matching selector
closest <selector> - - Next sibling matching selector
next <selector> - - Previous sibling matching selector
previous <selector> - - First child descendant
find <selector>
Swap strategies with :
hx-swap- (default) - Replace inner content
innerHTML - - Replace entire element
outerHTML - - Prepend inside target
afterbegin - - Insert before target
beforebegin - - Append inside target
beforeend - - Insert after target
afterend - - Delete target regardless of response
delete - - Don't swap content
none
Swap modifiers:
html
<button hx-get="/data" hx-swap="innerHTML swap:100ms settle:200ms">控制内容插入的位置和方式:
使用选择目标:
hx-targethtml
<button hx-get="/data" hx-target="#result">Load</button>
<div id="result"></div>扩展选择器:
- - 元素本身
this - - 匹配选择器的最近祖先元素
closest <selector> - - 匹配选择器的下一个兄弟元素
next <selector> - - 匹配选择器的上一个兄弟元素
previous <selector> - - 第一个匹配的子后代元素
find <selector>
使用设置交换策略:
hx-swap- (默认)- 替换目标内部内容
innerHTML - - 替换整个目标元素
outerHTML - - 在目标内部前置内容
afterbegin - - 在目标之前插入内容
beforebegin - - 在目标内部追加内容
beforeend - - 在目标之后插入内容
afterend - - 无论响应如何,删除目标元素
delete - - 不交换内容
none
交换修饰符:
html
<button hx-get="/data" hx-swap="innerHTML swap:100ms settle:200ms">Request Indicators
请求指示器
Show loading state during requests:
html
<button hx-get="/slow">
Click Me!
<img class="htmx-indicator" src="/spinner.gif">
</button>The class has by default. When request starts, class is added to the element, which makes indicators visible.
htmx-indicatoropacity:0htmx-requestSpecify custom indicator target:
html
<button hx-get="/data" hx-indicator="#loading">Load</button>
<div id="loading" class="htmx-indicator">Loading...</div>在请求期间显示加载状态:
html
<button hx-get="/slow">
Click Me!
<img class="htmx-indicator" src="/spinner.gif">
</button>htmx-indicatoropacity:0htmx-request指定自定义指示器目标:
html
<button hx-get="/data" hx-indicator="#loading">Load</button>
<div id="loading" class="htmx-indicator">Loading...</div>Common Patterns
常见模式
Active Search
实时搜索
html
<input type="text" name="q"
hx-get="/search"
hx-trigger="keyup changed delay:500ms"
hx-target="#search-results"
placeholder="Search...">
<div id="search-results"></div>html
<input type="text" name="q"
hx-get="/search"
hx-trigger="keyup changed delay:500ms"
hx-target="#search-results"
placeholder="Search...">
<div id="search-results"></div>Infinite Scroll
无限滚动
html
<div hx-get="/more-items"
hx-trigger="revealed"
hx-swap="afterend">
Load More...
</div>html
<div hx-get="/more-items"
hx-trigger="revealed"
hx-swap="afterend">
Load More...
</div>Click to Edit
点击编辑
html
<div hx-get="/edit/123" hx-target="this" hx-swap="outerHTML">
<label>Name:</label> John Doe
</div>html
<div hx-get="/edit/123" hx-target="this" hx-swap="outerHTML">
<label>Name:</label> John Doe
</div>Delete with Confirmation
确认删除
html
<button hx-delete="/item/123"
hx-confirm="Are you sure?"
hx-target="closest tr"
hx-swap="outerHTML swap:1s">
Delete
</button>html
<button hx-delete="/item/123"
hx-confirm="Are you sure?"
hx-target="closest tr"
hx-swap="outerHTML swap:1s">
Delete
</button>Out-of-Band Swaps
带外交换
Update multiple parts of the page from one response:
html
<!-- Response HTML -->
<div id="main-content">Main update</div>
<div id="notification" hx-swap-oob="true">
New notification!
</div>The element with swaps into its matching ID anywhere on the page.
hx-swap-oob="true"通过一次响应更新页面的多个部分:
html
<!-- 响应HTML -->
<div id="main-content">Main update</div>
<div id="notification" hx-swap-oob="true">
New notification!
</div>带有的元素会替换页面中ID匹配的元素。
hx-swap-oob="true"Form Handling
表单处理
Basic Form Submission
基本表单提交
html
<form hx-post="/submit" hx-target="#result">
<input name="email" type="email">
<button type="submit">Submit</button>
</form>html
<form hx-post="/submit" hx-target="#result">
<input name="email" type="email">
<button type="submit">Submit</button>
</form>Including Additional Values
包含额外值
html
<!-- Include other elements -->
<button hx-post="/save"
hx-include="[name='email']">
Save
</button>
<!-- Add extra values -->
<button hx-post="/save"
hx-vals='{"priority": "high"}'>
Save
</button>html
<!-- 包含其他元素的值 -->
<button hx-post="/save"
hx-include="[name='email']">
Save
</button>
<!-- 添加额外值 -->
<button hx-post="/save"
hx-vals='{"priority": "high"}'>
Save
</button>File Upload
文件上传
html
<form hx-post="/upload"
hx-encoding="multipart/form-data"
hx-target="#result">
<input type="file" name="file">
<button type="submit">Upload</button>
</form>Listen for upload progress:
javascript
htmx.on('htmx:xhr:progress', function(evt) {
htmx.find('#progress').value = evt.detail.loaded/evt.detail.total * 100;
});html
<form hx-post="/upload"
hx-encoding="multipart/form-data"
hx-target="#result">
<input type="file" name="file">
<button type="submit">Upload</button>
</form>监听上传进度:
javascript
htmx.on('htmx:xhr:progress', function(evt) {
htmx.find('#progress').value = evt.detail.loaded/evt.detail.total * 100;
});Request Synchronization
请求同步
Coordinate requests between elements with :
hx-synchtml
<form hx-post="/store">
<input name="title"
hx-post="/validate"
hx-trigger="change"
hx-sync="closest form:abort">
<button type="submit">Submit</button>
</form>Strategies:
- - Drop this request if target is in flight
drop - - Abort target request if this triggers
abort - - Abort target and issue this request
replace - - Queue this request after target
queue
使用协调元素之间的请求:
hx-synchtml
<form hx-post="/store">
<input name="title"
hx-post="/validate"
hx-trigger="change"
hx-sync="closest form:abort">
<button type="submit">Submit</button>
</form>策略:
- - 如果目标请求正在进行,丢弃当前请求
drop - - 如果当前请求触发,终止目标请求
abort - - 终止目标请求并发送当前请求
replace - - 在目标请求完成后排队发送当前请求
queue
Boosting
增强功能
Progressive enhancement for regular links and forms:
html
<div hx-boost="true">
<a href="/page1">Page 1</a>
<a href="/page2">Page 2</a>
</div>Links and forms become AJAX requests that target the body. Works without JavaScript enabled (graceful degradation).
为常规链接和表单提供渐进式增强:
html
<div hx-boost="true">
<a href="/page1">Page 1</a>
<a href="/page2">Page 2</a>
</div>链接和表单会变成以body为目标的AJAX请求。在禁用JavaScript时仍可正常工作(优雅降级)。
History Support
历史记录支持
Add URLs to browser history:
html
<a hx-get="/blog" hx-push-url="true">Blog</a>When user clicks back button, htmx restores the previous state. For history to work, URLs must return complete pages when visited directly.
Disable history caching for sensitive data:
html
<div hx-history="false">Sensitive content</div>将URL添加到浏览器历史记录:
html
<a hx-get="/blog" hx-push-url="true">Blog</a>当用户点击返回按钮时,htmx会恢复之前的状态。要使历史记录功能正常工作,直接访问URL时必须返回完整页面。
禁用敏感数据的历史记录缓存:
html
<div hx-history="false">Sensitive content</div>Headers
请求头
Request Headers
请求头
htmx automatically sends:
- - Identifies htmx requests
HX-Request: true - - ID of triggering element
HX-Trigger - - ID of target element
HX-Target - - Current page URL
HX-Current-URL - - User response to prompt
HX-Prompt
Use these to return partial HTML vs full pages:
python
if request.headers.get('HX-Request'):
return render_template('partial.html')
return render_template('full_page.html')htmx会自动发送以下请求头:
- - 标识htmx请求
HX-Request: true - - 触发元素的ID
HX-Trigger - - 目标元素的ID
HX-Target - - 当前页面URL
HX-Current-URL - - 用户对提示的响应
HX-Prompt
可以使用这些请求头来返回部分HTML还是完整页面:
python
if request.headers.get('HX-Request'):
return render_template('partial.html')
return render_template('full_page.html')Response Headers
响应头
Control client behavior from server:
- - Trigger client-side events
HX-Trigger - - Client-side redirect (full page)
HX-Redirect - - Client-side redirect (AJAX)
HX-Location - - Force page refresh
HX-Refresh - - Change target element
HX-Retarget - - Change swap strategy
HX-Reswap
python
response.headers['HX-Trigger'] = 'itemUpdated'
response.headers['HX-Trigger'] = '{"showMessage": "Saved!"}'通过服务器控制客户端行为:
- - 触发客户端事件
HX-Trigger - - 客户端重定向(整页)
HX-Redirect - - 客户端重定向(AJAX)
HX-Location - - 强制页面刷新
HX-Refresh - - 更改目标元素
HX-Retarget - - 更改交换策略
HX-Reswap
python
response.headers['HX-Trigger'] = 'itemUpdated'
response.headers['HX-Trigger'] = '{"showMessage": "Saved!"}'Validation
验证
htmx integrates with HTML5 validation:
html
<form hx-post="/submit">
<input name="email" type="email" required>
<button type="submit">Submit</button>
</form>Set to show validation messages.
htmx.config.reportValidityOfForms = trueCustom validation:
javascript
htmx.on('htmx:validation:validate', function(evt) {
if (evt.target.value === 'forbidden') {
evt.target.setCustomValidity('This value is forbidden');
evt.detail.valid = false;
}
});htmx与HTML5验证集成:
html
<form hx-post="/submit">
<input name="email" type="email" required>
<button type="submit">Submit</button>
</form>设置以显示验证消息。
htmx.config.reportValidityOfForms = true自定义验证:
javascript
htmx.on('htmx:validation:validate', function(evt) {
if (evt.target.value === 'forbidden') {
evt.target.setCustomValidity('This value is forbidden');
evt.detail.valid = false;
}
});Events and Scripting
事件与脚本
Event Handling
事件处理
Use for inline event handlers:
hx-onhtml
<button hx-get="/data"
hx-on::before-request="this.classList.add('loading')"
hx-on::after-request="this.classList.remove('loading')">
Load
</button>使用设置内联事件处理程序:
hx-onhtml
<button hx-get="/data"
hx-on::before-request="this.classList.add('loading')"
hx-on::after-request="this.classList.remove('loading')">
Load
</button>JavaScript API
JavaScript API
javascript
// Trigger requests programmatically
htmx.ajax('GET', '/data', '#target');
// Listen to events
htmx.on('htmx:afterSwap', function(evt) {
console.log('Content swapped');
});
// Process new content
htmx.process(document.body);
// Trigger events
htmx.trigger('#element', 'myEvent', {detail: {foo: 'bar'}});javascript
// 以编程方式触发请求
htmx.ajax('GET', '/data', '#target');
// 监听事件
htmx.on('htmx:afterSwap', function(evt) {
console.log('Content swapped');
});
// 处理新内容
htmx.process(document.body);
// 触发事件
htmx.trigger('#element', 'myEvent', {detail: {foo: 'bar'}});CSS Transitions
CSS过渡
Keep element IDs stable across swaps for automatic transitions:
html
<!-- Before -->
<div id="content">Old content</div>
<!-- After (same ID) -->
<div id="content" class="highlight">New content</div>css
.highlight {
background-color: yellow;
transition: background-color 1s ease-in;
}htmx preserves the DOM element and transitions the class change.
在内容交换过程中保持元素ID稳定以实现自动过渡:
html
<!-- 交换前 -->
<div id="content">Old content</div>
<!-- 交换后(相同ID) -->
<div id="content" class="highlight">New content</div>css
.highlight {
background-color: yellow;
transition: background-color 1s ease-in;
}htmx会保留DOM元素并过渡类的变化。
Configuration
配置
Configure globally or via meta tag:
html
<meta name="htmx-config" content='{
"defaultSwapStyle": "outerHTML",
"defaultSwapDelay": 100,
"defaultSettleDelay": 200,
"historyCacheSize": 20
}'>Or in JavaScript:
javascript
htmx.config.defaultSwapStyle = 'outerHTML';
htmx.config.timeout = 5000; // 5 second timeout全局配置或通过meta标签配置:
html
<meta name="htmx-config" content='{
"defaultSwapStyle": "outerHTML",
"defaultSwapDelay": 100,
"defaultSettleDelay": 200,
"historyCacheSize": 20
}'>或在JavaScript中配置:
javascript
htmx.config.defaultSwapStyle = 'outerHTML';
htmx.config.timeout = 5000; // 5秒超时Installation
安装
CDN (Recommended for quick start)
CDN(推荐快速入门使用)
html
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/htmx.min.js"></script>html
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/htmx.min.js"></script>npm
npm
bash
npm install htmx.org@2.0.8Then import:
javascript
import 'htmx.org';bash
npm install htmx.org@2.0.8然后导入:
javascript
import 'htmx.org';Download
下载
Download from jsDelivr and include locally:
html
<script src="/js/htmx.min.js"></script>从jsDelivr下载并本地引入:
html
<script src="/js/htmx.min.js"></script>Best Practices
最佳实践
- Keep IDs stable - Use consistent IDs across requests for CSS transitions
- Return appropriate content - Return partials for htmx requests, full pages for direct access
- Use semantic HTML - htmx enhances HTML, so start with good markup
- Progressive enhancement - Use so features work without JavaScript
hx-boost - Handle errors - Listen to and
htmx:responseErroreventshtmx:sendError - Validate inputs - Enable
htmx.config.reportValidityOfForms = true - Test without JavaScript - Ensure core functionality works when JS is disabled
- 保持ID稳定 - 在请求之间使用一致的ID以实现CSS过渡
- 返回合适的内容 - 为htmx请求返回部分HTML,为直接访问返回完整页面
- 使用语义化HTML - htmx是增强HTML的工具,因此从良好的标记开始
- 渐进式增强 - 使用确保在禁用JavaScript时功能仍可使用
hx-boost - 处理错误 - 监听和
htmx:responseError事件htmx:sendError - 验证输入 - 启用
htmx.config.reportValidityOfForms = true - 在无JavaScript环境下测试 - 确保核心功能在禁用JS时仍能正常工作
Debugging
调试
Enable logging:
javascript
htmx.logAll();Or set custom logger:
javascript
htmx.logger = function(elt, event, data) {
if(console) {
console.log(event, elt, data);
}
}Use browser DevTools to inspect:
- Network tab for request/response details
- headers in request/response
HX-* - Event listeners on elements
- classes during swap lifecycle
htmx-*
启用日志:
javascript
htmx.logAll();或设置自定义日志记录器:
javascript
htmx.logger = function(elt, event, data) {
if(console) {
console.log(event, elt, data);
}
}使用浏览器开发者工具检查:
- 网络标签页查看请求/响应详情
- 请求/响应中的头
HX-* - 元素上的事件监听器
- 交换生命周期中的类
htmx-*
Additional Resources
额外资源
For comprehensive details:
- - Complete attribute reference
references/attributes.md - - All htmx events and lifecycle
references/events.md - - Advanced patterns and real-world examples
references/examples.md - - Server-side implementation patterns
references/server-side.md
如需详细信息:
- - 完整的属性参考
references/attributes.md - - 所有htmx事件和生命周期
references/events.md - - 高级模式和真实示例
references/examples.md - - 服务器端实现模式
references/server-side.md