x-on 事件处理 #
什么是 x-on? #
x-on 指令用于监听 DOM 事件并执行相应的处理代码。它是实现用户交互的核心指令。
基本语法 #
完整语法:
html
<button x-on:事件名="处理代码"></button>
简写语法(推荐):
html
<button @事件名="处理代码"></button>
基本用法 #
点击事件 #
html
<div x-data="{ count: 0 }">
<button @click="count++">点击次数: <span x-text="count"></span></button>
</div>
调用方法 #
html
<div x-data="{
message: '',
greet() {
this.message = 'Hello!'
}
}">
<button @click="greet()">问候</button>
<p x-text="message"></p>
</div>
传递参数 #
html
<div x-data="{
result: 0,
add(a, b) {
this.result = a + b
}
}">
<button @click="add(5, 3)">计算 5 + 3</button>
<p>结果: <span x-text="result"></span></p>
</div>
访问事件对象 #
html
<div x-data>
<button @click="alert($event.target.textContent)">
点击我
</button>
</div>
内联处理 #
html
<div x-data="{ show: false }">
<button @click="show = !show">切换</button>
<div x-show="show">内容</div>
</div>
常用事件 #
鼠标事件 #
html
<div x-data="{
handleClick() { console.log('点击') },
handleDblClick() { console.log('双击') },
handleMouseDown() { console.log('鼠标按下') },
handleMouseUp() { console.log('鼠标释放') },
handleMouseEnter() { console.log('鼠标进入') },
handleMouseLeave() { console.log('鼠标离开') },
handleMouseMove() { console.log('鼠标移动') }
}">
<div
@click="handleClick()"
@dblclick="handleDblClick()"
@mousedown="handleMouseDown()"
@mouseup="handleMouseUp()"
@mouseenter="handleMouseEnter()"
@mouseleave="handleMouseLeave()"
@mousemove="handleMouseMove()"
style="padding: 50px; background: #f0f0f0;"
>
鼠标事件区域
</div>
</div>
键盘事件 #
html
<div x-data="{
handleKeydown(e) { console.log('按下:', e.key) },
handleKeyup(e) { console.log('释放:', e.key) }
}">
<input
@keydown="handleKeydown($event)"
@keyup="handleKeyup($event)"
placeholder="按下键盘"
>
</div>
表单事件 #
html
<div x-data="{
value: '',
handleSubmit() { console.log('提交:', this.value) },
handleInput(e) { console.log('输入:', e.target.value) },
handleChange(e) { console.log('改变:', e.target.value) },
handleFocus() { console.log('聚焦') },
handleBlur() { console.log('失焦') }
}">
<form @submit.prevent="handleSubmit()">
<input
x-model="value"
@input="handleInput($event)"
@change="handleChange($event)"
@focus="handleFocus()"
@blur="handleBlur()"
>
<button type="submit">提交</button>
</form>
</div>
事件修饰符 #
.prevent #
阻止默认行为(相当于 event.preventDefault()):
html
<form @submit.prevent="handleSubmit()">
<button type="submit">提交</button>
</form>
<a href="https://example.com" @click.prevent="handleClick()">
链接
</a>
.stop #
阻止事件冒泡(相当于 event.stopPropagation()):
html
<div @click="handleOuter()">
<button @click.stop="handleInner()">
点击不会触发外层事件
</button>
</div>
.once #
只触发一次:
html
<button @click.once="handleClick()">
只能点击一次
</button>
.capture #
使用捕获模式:
html
<div @click.capture="handleCapture()">
<button @click="handleBubble()">点击</button>
</div>
.self #
只在事件目标是当前元素时触发:
html
<div @click.self="handleClick()" style="padding: 20px; background: #f0f0f0;">
<button>点击按钮不会触发 div 的事件</button>
</div>
.passive #
提升移动端滚动性能:
html
<div @scroll.passive="handleScroll()">
滚动内容
</div>
.away #
点击元素外部时触发:
html
<div x-data="{ open: false }">
<button @click="open = true">打开</button>
<div
x-show="open"
@click.away="open = false"
style="padding: 20px; background: #f0f0f0;"
>
点击外部关闭
</div>
</div>
.debounce #
防抖处理:
html
<input
@input.debounce="search()"
placeholder="搜索..."
>
指定防抖时间:
html
<input
@input.debounce.500ms="search()"
placeholder="搜索..."
>
.throttle #
节流处理:
html
<button @click.throttle="handleClick()">
限制点击频率
</button>
指定节流时间:
html
<button @click.throttle.1000ms="handleClick()">
每秒最多触发一次
</button>
按键修饰符 #
常用按键 #
html
<input @keyup.enter="submit()">
<input @keyup.tab="next()">
<input @keyup.escape="cancel()">
<input @keyup.space="toggle()">
<input @keyup.up="moveUp()">
<input @keyup.down="moveDown()">
<input @keyup.left="moveLeft()">
<input @keyup.right="moveRight()">
组合键 #
html
<div @keydown.ctrl.s="save()"></div>
<div @keydown.ctrl.enter="submit()"></div>
<div @keydown.shift.enter="newLine()"></div>
<div @keydown.alt.s="saveAs()"></div>
<div @keydown.meta.s="save()"></div>
自定义按键码 #
html
<input @keyup.13="submit()">
鼠标修饰符 #
按键组合 #
html
<div @click.left="handleLeftClick()">左键点击</div>
<div @click.right="handleRightClick()">右键点击</div>
<div @click.middle="handleMiddleClick()">中键点击</div>
组合修饰符 #
html
<div @click.ctrl="handleCtrlClick()">Ctrl + 点击</div>
<div @click.shift="handleShiftClick()">Shift + 点击</div>
<div @click.alt="handleAltClick()">Alt + 点击</div>
<div @click.meta="handleMetaClick()">Meta + 点击</div>
实用示例 #
下拉菜单 #
html
<div x-data="{ open: false }" class="dropdown">
<button @click="open = !open">
菜单
</button>
<div
x-show="open"
@click.away="open = false"
class="dropdown-menu"
>
<a href="#" @click.prevent="open = false">选项 1</a>
<a href="#" @click.prevent="open = false">选项 2</a>
<a href="#" @click.prevent="open = false">选项 3</a>
</div>
</div>
模态框 #
html
<div x-data="{ open: false }">
<button @click="open = true">打开模态框</button>
<div
x-show="open"
x-transition
@keydown.escape.window="open = false"
class="modal-overlay"
@click.self="open = false"
>
<div class="modal-content" @click.stop>
<h2>模态框标题</h2>
<p>内容</p>
<button @click="open = false">关闭</button>
</div>
</div>
</div>
拖拽功能 #
html
<div x-data="{
dragging: false,
x: 0,
y: 0,
startX: 0,
startY: 0,
startDrag(e) {
this.dragging = true
this.startX = e.clientX - this.x
this.startY = e.clientY - this.y
},
onDrag(e) {
if (!this.dragging) return
this.x = e.clientX - this.startX
this.y = e.clientY - this.startY
},
endDrag() {
this.dragging = false
}
}" @mousemove.window="onDrag($event)" @mouseup.window="endDrag()">
<div
@mousedown="startDrag($event)"
:style="`transform: translate(${x}px, ${y}px)`"
class="draggable"
>
拖拽我
</div>
</div>
快捷键 #
html
<div x-data="{
showHelp: false,
save() { console.log('保存') },
undo() { console.log('撤销') },
redo() { console.log('重做') },
copy() { console.log('复制') },
paste() { console.log('粘贴') }
}" @keydown.window.ctrl.s.prevent="save()" @keydown.window.ctrl.z.prevent="undo()" @keydown.window.ctrl.y.prevent="redo()" @keydown.window.ctrl.c.prevent="copy()" @keydown.window.ctrl.v.prevent="paste()" @keydown.window.slash="showHelp = !showHelp">
<p>快捷键:</p>
<ul>
<li>Ctrl+S: 保存</li>
<li>Ctrl+Z: 撤销</li>
<li>Ctrl+Y: 重做</li>
<li>/: 帮助</li>
</ul>
<div x-show="showHelp" @click.away="showHelp = false">
帮助信息
</div>
</div>
搜索输入 #
html
<div x-data="{
query: '',
results: [],
async search() {
if (this.query.length < 2) {
this.results = []
return
}
const res = await fetch(`/api/search?q=${this.query}`)
this.results = await res.json()
}
}">
<input
x-model="query"
@input.debounce.300ms="search()"
@keydown.escape="results = []"
@keydown.up="selectPrevious()"
@keydown.down="selectNext()"
@keydown.enter="selectCurrent()"
placeholder="搜索..."
>
<ul x-show="results.length > 0">
<template x-for="result in results" :key="result.id">
<li x-text="result.name"></li>
</template>
</ul>
</div>
右键菜单 #
html
<div x-data="{
show: false,
x: 0,
y: 0,
openMenu(e) {
e.preventDefault()
this.show = true
this.x = e.clientX
this.y = e.clientY
}
}" @contextmenu="openMenu($event)" @click.away="show = false">
右键点击这里
<div
x-show="show"
x-transition
:style="`position: fixed; left: ${x}px; top: ${y}px`"
class="context-menu"
>
<div @click="show = false">选项 1</div>
<div @click="show = false">选项 2</div>
<div @click="show = false">选项 3</div>
</div>
</div>
复制到剪贴板 #
html
<div x-data="{
text: 'Hello World',
copied: false,
async copy() {
await navigator.clipboard.writeText(this.text)
this.copied = true
setTimeout(() => this.copied = false, 2000)
}
}">
<input :value="text" readonly>
<button @click="copy()">
<span x-show="!copied">复制</span>
<span x-show="copied">已复制!</span>
</button>
</div>
注意事项 #
1. 方法调用 #
需要显式调用方法:
html
<button @click="handleClick()">正确</button>
<button @click="handleClick">错误(不会执行)</button>
2. 事件对象 #
内联表达式中可直接使用 $event:
html
<button @click="console.log($event)">点击</button>
3. 修饰符顺序 #
修饰符按顺序执行:
html
<button @click.stop.prevent="handler()">
先 stop 再 prevent
</button>
小结 #
x-on 指令要点:
- 使用
@简写语法监听事件 - 支持各种 DOM 事件
- 提供丰富的事件修饰符
- 支持按键和鼠标修饰符
- 支持防抖和节流
下一章,我们将学习 x-init 指令进行初始化。
最后更新:2026-03-28