Skip to content

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" />

性能优化建议

  1. 合理使用 .passive

    vue
    <!-- 移动端滚动事件,添加 passive 提升性能 -->
    <div @scroll.passive="onScroll"></div>
  2. 避免过度使用修饰符

    vue
    <!-- 不推荐:过于复杂的修饰符链 -->
    <button @click.stop.prevent.self.once.right="doSomething">
  3. 考虑使用事件处理函数

    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模板语法的重要特性,它们使事件处理更加声明式和简洁。正确使用修饰符可以提高代码可读性和开发效率。