Vue事件修饰符详解
事件修饰符是Vue中用于处理DOM事件细节的特殊后缀,通过点.表示。它们允许我们在模板中声明式地处理事件,而不需要在方法中编写额外的逻辑。
常用事件修饰符
1. .stop
阻止事件冒泡(传播)
vue
<!-- 点击按钮时,不会触发父元素的click事件 -->
<div @click="parentClick">
<button @click.stop="childClick">按钮</button>
</div>
<!-- 等同于JavaScript中的 event.stopPropagation() -->2. .prevent
阻止默认行为
vue
<!-- 提交表单不会刷新页面 -->
<form @submit.prevent="onSubmit">
<button type="submit">提交</button>
</form>
<!-- 等同于 event.preventDefault() -->3. .capture
使用事件捕获模式(从外到内)
vue
<!-- 先触发父元素,再触发子元素(默认是冒泡:从内到外) -->
<div @click.capture="parentClick">
<button @click="childClick">按钮</button>
</div>
<!-- 事件流:捕获阶段 → 目标阶段 → 冒泡阶段 -->4. .self
只有当事件是从触发元素自身触发时才调用
vue
<!-- 只有点击div本身才触发,点击子元素不触发 -->
<div @click.self="handleClick">
<p>点击这个文字不会触发div的click事件</p>
</div>
<!-- 等同于:if (event.target !== event.currentTarget) return -->5. .once
事件只触发一次
vue
<!-- 按钮只能点击一次 -->
<button @click.once="handleClick">只能点一次</button>6. .passive
告诉浏览器不会调用preventDefault(),用于优化滚动性能
vue
<!-- 移动端优化滚动性能 -->
<div @scroll.passive="onScroll">滚动内容</div>
<!-- 特别适合移动端的touch事件 -->
<div @touchmove.passive="onTouchMove"></div>按键修饰符
1. 按键别名
vue
<!-- 只有按下回车键时触发 -->
<input @keyup.enter="submit">
<!-- 常用按键别名 -->
<input @keyup.enter="submit"> <!-- 回车 -->
<input @keyup.tab="next"> <!-- Tab -->
<input @keyup.delete="deleteItem"> <!-- 删除/退格 -->
<input @keyup.esc="cancel"> <!-- ESC -->
<input @keyup.space="pause"> <!-- 空格 -->
<input @keyup.up="moveUp"> <!-- 上箭头 -->
<input @keyup.down="moveDown"> <!-- 下箭头 -->2. 系统修饰键
vue
<!-- 组合按键 -->
<input @keyup.ctrl.enter="ctrlEnter"> <!-- Ctrl + Enter -->
<button @click.ctrl="ctrlClick"> <!-- 按住Ctrl点击 -->
<!-- 常用系统修饰键 -->
@keyup.ctrl <!-- Ctrl键 -->
@keyup.alt <!-- Alt键 -->
@keyup.shift <!-- Shift键 -->
@keyup.meta <!-- Windows键 / Command键 -->3. 精确修饰符
vue
<!-- .exact 精确控制系统修饰符的组合 -->
<button @click="anyClick">点击任何键都可以触发</button>
<button @click.ctrl="ctrlClick">Ctrl + 点击(可以组合其他键)</button>
<button @click.ctrl.exact="onlyCtrlClick">仅Ctrl + 点击</button>
<button @click.exact="noModifierClick">没有任何系统修饰键时点击</button>鼠标按键修饰符
vue
<!-- 指定鼠标按键 -->
<button @click.left="leftClick"> 左键点击</button>
<button @click.right="rightClick"> 右键点击</button>
<button @click.middle="middleClick">中键点击</button>修饰符组合使用
1. 顺序很重要
vue
<!-- 1. 先阻止冒泡,再阻止默认 -->
<a @click.stop.prevent="doThis"></a>
<!-- 2. 多个修饰符可以串联 -->
<form @submit.stop.prevent></form>
<!-- 3. 按键和鼠标组合 -->
<input @keyup.ctrl.alt.delete="emergency">2. 常见组合示例
vue
<template>
<!-- 阻止表单默认提交和事件冒泡 -->
<form @submit.prevent.stop="handleSubmit">
<input type="text" v-model="name">
<button type="submit">提交</button>
</form>
<!-- 右键菜单,阻止默认上下文菜单 -->
<div @contextmenu.prevent="showCustomMenu">
右键点击我
</div>
<!-- 键盘快捷键 -->
<div
@keydown.ctrl.s.prevent="saveDocument"
tabindex="0"
style="outline: none;"
>
按 Ctrl+S 保存
</div>
<!-- 移动端优化 -->
<div
@touchstart.passive="touchStart"
@touchmove.passive="touchMove"
>
触摸区域
</div>
</template>
<script setup>
import { ref } from 'vue'
const name = ref('')
const handleSubmit = () => {
console.log('提交表单,name:', name.value)
}
const showCustomMenu = (event) => {
console.log('显示自定义菜单', event.clientX, event.clientY)
}
const saveDocument = () => {
console.log('保存文档')
}
const touchStart = (event) => {
console.log('触摸开始')
}
const touchMove = (event) => {
console.log('触摸移动')
}
</script>Vue 3 中的变化
1. 移除的修饰符
vue
<!-- Vue 2 中的 .native 修饰符已被移除 -->
<!-- Vue 2: -->
<my-component @click.native="handleClick"></my-component>
<!-- Vue 3: 组件现在默认不监听原生事件 -->
<!-- 需要在组件内部声明 emits -->2. 新增的修饰符
Vue 3 支持更多按键别名:
vue
<!-- Vue 3 新增了一些按键别名 -->
<input @keyup.page-down="pageDown"> <!-- PageDown -->
<input @keyup.page-up="pageUp"> <!-- PageUp -->
<input @keyup.home="goHome"> <!-- Home -->
<input @keyup.end="goEnd"> <!-- End -->3. v-model 修饰符
vue
<!-- .lazy - 在 change 事件后同步(而不是 input) -->
<input v-model.lazy="message">
<!-- .number - 自动将输入转为数字 -->
<input v-model.number="age" type="number">
<!-- .trim - 自动去除首尾空格 -->
<input v-model.trim="username">自定义修饰符
1. 全局自定义修饰符
javascript
// main.js
app.config.globalProperties.$customModifiers = {
uppercase: {
beforeWrite(value) {
return value.toUpperCase()
}
}
}
// 使用
<input v-model.uppercase="text">2. 组件自定义修饰符
vue
<!-- CustomInput.vue -->
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
>
</template>
<script>
export default {
props: {
modelValue: String,
modelModifiers: {
default: () => ({})
}
},
created() {
// 检查是否使用了自定义修饰符
if (this.modelModifiers.uppercase) {
// 处理逻辑
}
}
}
</script>
<!-- 使用 -->
<custom-input v-model.uppercase="text" />性能优化建议
合理使用
.passivevue<!-- 移动端滚动事件,添加 passive 提升性能 --> <div @scroll.passive="onScroll"></div>避免过度使用修饰符
vue<!-- 不推荐:过于复杂的修饰符链 --> <button @click.stop.prevent.self.once.right="doSomething">考虑使用事件处理函数
vue<!-- 复杂的逻辑更适合放在方法中 --> <button @click="handleComplexClick"> 复杂操作 </button> <script> const handleComplexClick = (event) => { event.stopPropagation() event.preventDefault() if (event.shiftKey) { // 处理Shift点击 } // 更多逻辑... } </script>
实用示例
vue
<template>
<!-- 右键保存图片 -->
<img
src="image.jpg"
@contextmenu.prevent.right="saveImage"
alt="示例图片"
>
<!-- 快捷键提交 -->
<form @keydown.ctrl.enter.prevent="submitForm">
<textarea v-model="content"></textarea>
</form>
<!-- 滚动加载更多 -->
<div
class="scroll-container"
@scroll.passive="onScroll"
>
<!-- 内容 -->
</div>
<!-- 防止双击误操作 -->
<button @click.once="processPayment">
确认支付(只能点一次)
</button>
</template>
<script setup>
import { ref } from 'vue'
const saveImage = (event) => {
console.log('保存图片,坐标:', event.clientX, event.clientY)
}
const content = ref('')
const submitForm = () => {
console.log('使用 Ctrl+Enter 提交表单')
}
const onScroll = (event) => {
const { scrollTop, clientHeight, scrollHeight } = event.target
if (scrollTop + clientHeight >= scrollHeight - 50) {
loadMore()
}
}
const loadMore = () => {
console.log('加载更多数据')
}
const processPayment = () => {
console.log('支付处理中...')
}
</script>事件修饰符是Vue模板语法的重要特性,它们使事件处理更加声明式和简洁。正确使用修饰符可以提高代码可读性和开发效率。
