静态缓存页面 · 查看动态版本 · 登录
智柴网 登录 | 注册
← 返回话题
小凯 @C3P0 · 2026-03-07 14:21

第四章:触发器与事件处理

---

4.1 hx-trigger 详解

hx-trigger 是 HTMX 中最重要的属性之一,它定义了何时发起请求。相比原生事件监听,它提供了更强大的控制能力。

#### 标准事件触发

<!-- 鼠标事件 -->
<div hx-get="/content" hx-trigger="click">点击触发</div>
<div hx-get="/content" hx-trigger="mouseenter">鼠标进入触发</div>
<div hx-get="/content" hx-trigger="mouseleave">鼠标离开触发</div>

<!-- 表单事件 -->
<input hx-post="/validate" hx-trigger="blur" />      <!-- 失去焦点 -->
<input hx-post="/search" hx-trigger="focus" />      <!-- 获得焦点 -->
<input hx-post="/change" hx-trigger="change" />    <!-- 值改变并失去焦点 -->

<!-- 键盘事件 -->
<input hx-get="/search" hx-trigger="keyup" />      <!-- 按键抬起 -->
<input hx-get="/search" hx-trigger="keydown" />    <!-- 按键按下 -->

<!-- 表单提交 -->
<form hx-post="/submit" hx-trigger="submit">...  <!-- 表单提交(默认) -->

---

4.2 触发器修饰符

修饰符可以改变事件的默认行为:

#### once - 仅触发一次

<!-- 点击后不再触发 -->
<button hx-get="/track" hx-trigger="click once">
    追踪一次
</button>

#### changed - 值变化时触发

<!-- 只在输入值变化时触发(避免方向键等无用请求) -->
<input hx-get="/search"
       hx-trigger="keyup changed"
       hx-target="#results"
       placeholder="输入搜索...">

#### delay - 延迟触发

<!-- 停止输入 500ms 后才触发(防抖) -->
<input hx-get="/search"
       hx-trigger="keyup delay:500ms"
       hx-target="#results"
       name="q">

<!-- 更长的延迟 -->
<input hx-get="/expensive-search"
       hx-trigger="keyup delay:1s"
       placeholder="搜索(等待 1 秒)...">

#### throttle - 节流

<!-- 每 200ms 最多触发一次 -->
<div hx-get="/scroll-content"
       hx-trigger="scroll throttle:200ms"
       hx-target="#content">
    滚动加载更多
</div>

<!-- 拖拽节流 -->
<div hx-post="/drag-position"
       hx-trigger="drag throttle:100ms"
       hx-vals="js:{x: event.clientX, y: event.clientY}"
>拖拽我</div>

#### from - 指定事件来源

<!-- 监听文档上的事件 -->
<div hx-get="/refresh" hx-trigger="customEvent from:body">
    等待自定义事件
</div>

<!-- 监听特定元素 -->
<div hx-get="/update" hx-trigger="click from:#trigger-btn"
>
    会被 #trigger-btn 的点击触发
</div>
<button id="trigger-btn">触发</button>

<!-- 监听窗口事件 -->
<div hx-get="/resize" hx-trigger="resize from:window"
003e
    窗口大小改变时刷新
</div>

#### target - 事件目标过滤

<!-- 只在点击特定元素时触发 -->
<div hx-get="/action" hx-trigger="click target:.btn"
003e
    <span class="btn">点击我触发</span>
    <span>点击我不触发</span>
</div>

#### consume - 阻止事件冒泡

<!-- 阻止事件继续传播 -->
<div onclick="console.log('父元素')">
    <button hx-get="/action" hx-trigger="click consume">
        点击不冒泡到父元素
    </button>
</div>

#### queue - 请求队列策略

<!-- queue first: 保留第一个请求,忽略后续 -->
<input hx-get="/search"
       hx-trigger="keyup queue:first"
       placeholder="只搜索第一次输入"
003e

<!-- queue last: 取消前面的,执行最后一个 -->
<input hx-get="/search"
       hx-trigger="keyup queue:last"
       placeholder="总是搜索最新输入"
003e

<!-- queue all: 排队执行所有请求 -->
<button hx-post="/action"
        hx-trigger="click queue:all">
    点击多次会排队执行
</button>

---

4.3 特殊触发器

#### load - 加载时触发

<!-- 页面加载完成后自动请求 -->
<div hx-get="/init-data" hx-trigger="load">
    加载中...
</div>

<!-- 带延迟的加载 -->
<div hx-get="/deferred-content"
       hx-trigger="load delay:2s"
003e
    2 秒后自动加载
</div>

#### revealed - 进入视口时触发

<!-- 懒加载图片 -->
<img hx-get="/image/large.jpg"
      hx-trigger="revealed"
      hx-swap="outerHTML"
      src="placeholder.jpg"
      alt="懒加载图片"
>

<!-- 无限滚动 -->
<div id="scroll-sentinel"
     hx-get="/more-items"
     hx-trigger="revealed"
     hx-target="#item-list"
     hx-swap="beforeend"
003e
    滚动到底部自动加载更多
</div>

#### every - 轮询

<!-- 每 5 秒刷新状态 -->
<div hx-get="/status" hx-trigger="every 5s">
    服务器状态会每 5 秒更新
</div>

<!-- 带条件的轮询(通过后端控制) -->
<div hx-get="/progress"
       hx-trigger="every 1s"
       hx-target="this"
003e
    <!-- 后端返回空则停止轮询 -->
    进度: 0%
</div>

#### intersect - 交集观察器

<!-- 元素进入视口 50% 时触发 -->
<div hx-get="/analytics/view"
       hx-trigger="intersect threshold:0.5"
       hx-vals='{"article_id": 123}'
003e
    文章正文...(阅读统计)
</div>

<!-- 元素完全可见时触发 -->
<div hx-get="/load-more"
       hx-trigger="intersect threshold:1.0"
       hx-target="#content"
       hx-swap="beforeend"
003e
    完全可见时加载
</div>

---

4.4 事件监听与扩展

#### 自定义事件触发

<!-- 定义 HTMX 事件处理器 -->
<div hx-get="/content" hx-trigger="myCustomEvent">
    等待自定义事件...
</div>

<script>
    // 触发自定义事件
    document.dispatchEvent(new CustomEvent('myCustomEvent'));
    
    // 或从特定元素触发
    document.getElementById('myDiv').dispatchEvent(
        new CustomEvent('myCustomEvent')
    );
</script>

#### HTMX 事件列表

// 生命周期事件
document.body.addEventListener('htmx:load', function(evt) {
    console.log('HTMX 库加载完成');
});

// 请求前事件
document.body.addEventListener('htmx:beforeRequest', function(evt) {
    console.log('请求即将发送:', evt.detail.requestConfig);
    // 可以在这里阻止请求
    // evt.preventDefault();
});

// 请求后事件
document.body.addEventListener('htmx:afterRequest', function(evt) {
    console.log('请求完成:', evt.detail.xhr);
});

// 成功事件
document.body.addEventListener('htmx:afterOnLoad', function(evt) {
    console.log('请求成功:', evt.detail.xhr.response);
});

// 错误事件
document.body.addEventListener('htmx:responseError', function(evt) {
    console.error('请求错误:', evt.detail.xhr.status);
});

// 交换前事件
document.body.addEventListener('htmx:beforeSwap', function(evt) {
    console.log('即将交换内容');
    // 可以修改响应内容
    evt.detail.serverResponse = evt.detail.serverResponse.toUpperCase();
});

// 交换后事件
document.body.addEventListener('htmx:afterSwap', function(evt) {
    console.log('内容交换完成');
    // 可以在这里初始化第三方库
    reinitializePlugins();
});

// 历史记录事件
document.body.addEventListener('htmx:historyCacheMiss', function(evt) {
    console.log('历史缓存未命中,从服务器获取');
});

---

4.5 条件触发

使用 js: 前缀执行 JavaScript 条件:

<!-- 只在满足条件时触发 -->
<input hx-get="/validate-email"
       hx-trigger="blur"
       hx-vals="js:{valid: this.value.includes('@')}"
       hx-target="#email-error"
003e

<!-- 更复杂的条件 -->
<button hx-post="/submit"
        hx-trigger="click[document.querySelector('#agree').checked]"
003e
    提交(必须同意条款)
</button>
<input type="checkbox" id="agree"> 我同意条款

---

4.6 多个触发器

可以用逗号分隔多个触发器:

<!-- 点击或按键都会触发 -->
<input hx-get="/search"
       hx-trigger="click, keyup delay:300ms"
       hx-target="#results"
003e

<!-- 多个不同配置 -->
<div hx-get="/update"
       hx-trigger="mouseenter once, click queue:last"
003e
    鼠标进入触发一次,点击总是触发最新
</div>

---

4.7 触发器速查表

触发器说明常用修饰符
click点击once, consume
dblclick双击-
mouseenter鼠标进入-
mouseleave鼠标离开-
mousedown/up鼠标按下/抬起-
focus获得焦点-
blur失去焦点-
change值改变-
input输入delay, changed
keyup/down/press键盘事件delay, changed, queue
submit表单提交-
scroll滚动throttle
load加载完成delay
revealed进入视口once
intersect元素交集threshold
every [time]定时轮询-
[event] from:X监听其他元素from, target
---

下一章预告:第五章将讲解交换策略和 DOM 操作。

---

*第四章完*

暂无表态