x-on
x-on 允许你轻松地处理分发的 DOM 事件。
以下是一个简单按钮的示例,点击时会显示一个警告框。
<button x-on:click="alert('Hello World!')">Say Hi</button>
x-on只能监听小写名称的事件,因为 HTML 属性不区分大小写。编写x-on:CLICK将监听名为click的事件。如果你需要监听使用 camelCase 名称的自定义事件,可以使用.camel辅助符 来解决此限制。或者,你可以使用x-bind在 JavaScript 代码中为元素附加x-on指令(此时大小写将保持不变)。
简写语法
如果 x-on: 对你来说过于冗长,你可以使用简写语法:@。
以下是上面同一个组件,但使用了简写语法:
<button @click="alert('Hello World!')">Say Hi</button>
尽管上述代码片段中没有包含,但如果没有父元素定义
x-data,则无法使用x-on。→ 阅读更多关于x-data
事件对象
如果你希望从表达式中访问原生 JavaScript 事件对象,可以使用 Alpine 的魔术属性 $event。
<button @click="alert($event.target.getAttribute('message'))" message="Hello World">Say Hi</button>
此外,Alpine 还会将事件对象传递给任何没有尾随括号的方法引用。例如:
<button @click="handleClick">...</button>
<script>
function handleClick(e) {
// 现在你可以直接访问事件对象 (e)
}
</script>
键盘事件
Alpine 使监听特定键的 keydown 和 keyup 事件变得简单。
以下是在输入元素中监听 Enter 键的示例:
<input type="text" @keyup.enter="alert('Submitted!')">
你还可以链式组合这些按键修饰符,以实现更复杂的监听。
以下是一个监听器,它在按住 Shift 键的同时按下 Enter 时触发,但在单独按下 Enter 时不触发。
<input type="text" @keyup.shift.enter="alert('Submitted!')">
你可以通过将键名转换为 kebab-case 形式,直接将 KeyboardEvent.key 暴露的任何有效键名用作修饰符。
<input type="text" @keyup.page-down="alert('Submitted!')">
为方便参考,以下是你可能想要监听的常用键列表。
| 修饰符 | 键盘键 |
|---|---|
.shift |
Shift |
.enter |
Enter |
.space |
Space |
.ctrl |
Ctrl |
.cmd |
Cmd |
.meta |
Mac 上为 Cmd,Windows 上为 Windows 键 |
.alt |
Alt |
.up .down .left .right |
上/下/左/右方向键 |
.escape |
Escape |
.tab |
Tab |
.caps-lock |
Caps Lock |
.equal |
等号 = |
.period |
句点 . |
.comma |
逗号 , |
.slash |
正斜杠 / |
鼠标事件
与上面的键盘事件类似,Alpine 允许使用一些按键修饰符来处理 click 事件。
| 修饰符 | 事件键 |
|---|---|
.shift |
shiftKey |
.ctrl |
ctrlKey |
.cmd |
metaKey |
.meta |
metaKey |
.alt |
altKey |
这些修饰符适用于 click、auxclick、context 和 dblclick 事件,甚至包括 mouseover、mousemove、mouseenter、mouseleave、mouseout、mouseup 和 mousedown。
以下是一个按钮的示例,当按住 Shift 键时其行为会发生变化。
<button type="button"
x-data="{ message: 'select' }"
@click="message = 'selected'"
@click.shift="message = 'added to selection'"
@mousemove.shift="message = 'add to selection'"
@mouseout="message = 'select'"
x-text="message"></button>
注意:带有某些修饰符(如
ctrl)的普通 click 事件在大多数浏览器中会自动变为contextmenu事件。类似地,右键点击会触发contextmenu事件,但如果contextmenu事件被阻止,也会触发auxclick事件。
自定义事件
Alpine 事件监听器是原生 DOM 事件监听器的封装。因此,它们可以监听任何 DOM 事件,包括自定义事件。
以下是一个组件示例,它分发了一个自定义 DOM 事件,同时也监听了该事件。
<div x-data @foo="alert('Button Was Clicked!')">
<button @click="$event.target.dispatchEvent(new CustomEvent('foo', { bubbles: true }))">...</button>
</div>
当按钮被点击时,@foo 监听器将被调用。
由于 .dispatchEvent API 较为冗长,Alpine 提供了 $dispatch 辅助工具来简化操作。
以下是使用 $dispatch 魔术属性重写的相同组件。
<div x-data @foo="alert('Button Was Clicked!')">
<button @click="$dispatch('foo')">...</button>
</div>
修饰符
Alpine 提供了许多指令修饰符,用于自定义事件监听器的行为。
.prevent
.prevent 相当于在监听器中调用浏览器事件对象上的 .preventDefault()。
<form @submit.prevent="console.log('submitted')" action="/foo">
<button>Submit</button>
</form>
在上面的示例中,使用 .prevent 后,点击按钮不会将表单提交到 /foo 端点。相反,Alpine 的监听器将处理它并"阻止"事件被进一步处理。
.stop
与 .prevent 类似,.stop 相当于在监听器中调用浏览器事件对象上的 .stopPropagation()。
<div @click="console.log('I will not get logged')">
<button @click.stop>Click Me</button>
</div>
在上面的示例中,点击按钮不会记录消息。这是因为我们立即停止了事件的传播,不允许它"冒泡"到带有 @click 监听器的 <div>。
.outside
.outside 是一个方便的辅助工具,用于监听在其所附加的元素外部发生的点击。以下是一个简单的下拉组件示例:
<div x-data="{ open: false }">
<button @click="open = ! open">Toggle</button>
<div x-show="open" @click.outside="open = false">
Contents...
</div>
</div>
在上面的示例中,通过点击"Toggle"按钮显示下拉内容后,你可以通过点击页面上下拉内容外部的任意位置来关闭下拉菜单。
这是因为 .outside 监听的是不从其注册元素发起的点击。
值得注意的是,
.outside表达式仅在其注册的元素在页面上可见时才会被求值。否则,会出现讨厌的竞争条件,点击"Toggle"按钮也会触发现有元素不可见的@click.outside处理程序。
.window
当存在 .window 修饰符时,Alpine 会将事件监听器注册到页面上的根 window 对象上,而不是元素本身。
<div @keyup.escape.window="...">...</div>
上面的代码片段将监听页面上任何位置按下"escape"键的事件。
在这些情况下,将 .window 添加到监听器非常有用,即你的标记中小部分内容关心在整个页面上发生的事件。
.document
.document 的工作方式类似于 .window,只是它将监听器注册到 document 全局对象上,而不是 window 全局对象。
.once
通过向监听器添加 .once,你可以确保处理程序仅被调用一次。
<button @click.once="console.log('I will only log once')">...</button>
.debounce
有时,对事件处理程序进行"防抖"非常有用,这样它只会在一定的不活动时间(默认为 250 毫秒)后调用。
例如,如果你有一个搜索字段,在用户键入时会触发网络请求,添加防抖可以防止在每次按键时都触发网络请求。
<input @input.debounce="fetchResults">
现在,fetchResults 不会在每次按键后被调用,而是在 250 毫秒没有按键操作后才会被调用。
如果你希望延长或缩短防抖时间,可以通过在 .debounce 修饰符后添加一个持续时间来实现:
<input @input.debounce.500ms="fetchResults">
现在,fetchResults 只会在 500 毫秒不活动后调用。
.throttle
.throttle 与 .debounce 类似,不同之处在于它会每 250 毫秒释放一次处理程序调用,而不是无限期地推迟。
这对于那些可能存在重复且长时间的事件触发,且使用 .debounce 无效的情况非常有用,因为你仍需定期处理该事件。
例如:
<div @scroll.window.throttle="handleScroll">...</div>
上面的示例是节流的一个很好的用例。没有 .throttle 时,当用户向下滚动页面时,handleScroll 方法可能会被触发数百次,这会严重拖慢网站速度。通过添加 .throttle,我们确保 handleScroll 每 250 毫秒只被调用一次。
有趣的是:本文档网站正是使用这种策略来更新右侧边栏中当前高亮的章节。
与 .debounce 一样,你可以为节流事件添加自定义持续时间:
<div @scroll.window.throttle.750ms="handleScroll">...</div>
现在,handleScroll 每 750 毫秒才会被调用一次。
.self
通过向事件监听器添加 .self,你可以确保事件是从声明该监听器的元素本身发出的,而不是来自子元素。
<button @click.self="handleClick">
Click Me
<img src="...">
</button>
在上面的示例中,<button> 标签内有一个 <img> 标签。通常情况下,任何从 <button> 元素内部(例如从 <img>)发出的点击,都会被按钮上的 @click 监听器捕获。
但是,在这种情况下,由于我们添加了 .self,只有点击按钮本身才会调用 handleClick。从 <img> 元素发出的点击将不会被处理。
.camel
<div @custom-event.camel="handleCustomEvent">
...
</div>
有时你可能希望监听 camelCase 形式的事件,例如示例中的 customEvent。由于 HTML 属性不支持驼峰命名,因此需要添加 .camel 修饰符,以便 Alpine 在内部将事件名称转换为驼峰形式。
通过在上面示例中添加 .camel,Alpine 现在监听的是 customEvent 而不是 custom-event。
.dot
<div @custom-event.dot="handleCustomEvent">
...
</div>
与 .camelCase 修饰符类似,在某些情况下你可能希望监听名称中包含点号的事件(如 custom.event)。由于事件名称中的点号被 Alpine 保留,你需要使用短横线书写并添加 .dot 修饰符。
在上面的代码示例中,custom-event.dot 对应于事件名称 custom.event。
.passive
浏览器优化页面滚动以使其快速流畅,即使在页面上执行 JavaScript 时也是如此。然而,实现不当的触摸和滚轮监听器可能会阻塞这种优化,并导致页面性能不佳。
如果你正在监听触摸事件,那么向监听器添加 .passive 以避免阻塞滚动性能非常重要。
<div @touchstart.passive="...">...</div>
.passive.false
在现代浏览器中,触摸和滚轮事件监听器默认是 passive 的。传递 .passive.false 可以使这些事件可取消,以便你可以对其调用 preventDefault。
<div @touchmove.passive.false="$event.preventDefault()">...</div>
.capture
如果你希望监听器在事件的捕获阶段执行,即在事件从目标元素向上冒泡到 DOM 之前执行,请添加此修饰符。
<div @click.capture="console.log('I will log first')">
<button @click="console.log('I will log second')"></button>
</div>