Vue修饰符

220 阅读3分钟

一、修饰符的本质与分类

定义:Vue 修饰符是添加在指令后缀的特殊符号,用于修改指令的行为,简化常见场景的代码逻辑。
分类

  1. 事件修饰符:优化事件处理(如 @click.prevent);
  2. 表单修饰符:处理表单输入(如 v-model.trim);
  3. 按键修饰符:监听特定按键(如 @keyup.enter);
  4. 系统修饰符:处理键盘/鼠标特殊操作(如 @click.ctrl);
  5. 组件修饰符:优化组件通信(如 .syncv-model 的修饰符)。

二、事件修饰符(最常用类别)

1. 核心事件修饰符
修饰符作用等价代码
.prevent阻止事件默认行为(如 a 标签跳转)event.preventDefault()
.stop阻止事件冒泡event.stopPropagation()
.capture使用事件捕获阶段(而非冒泡阶段)addEventListener('click', handler, { capture: true })
.self仅当事件发生在元素自身时触发if (event.target === event.currentTarget) {...}
.once事件只触发一次event.addEventListener('click', handler, { once: true })
2. 示例与最佳实践
<!-- 阻止表单提交默认行为 -->
<form @submit.prevent="handleSubmit">...</form>

<!-- 阻止事件冒泡(如弹窗蒙层点击) -->
<div class="modal" @click.stop="closeModal">
  <div class="content" @click="doNotClose">...</div>
</div>

<!-- 事件只触发一次(如初始化按钮) -->
<button @click.once="initSystem">初始化系统</button>

三、表单修饰符(v-model 增强)

1. 常用表单修饰符
  • .trim:自动过滤输入首尾空格
    <input v-model.trim="username" />
    
  • .number:将输入转为数字(否则为字符串)
    <input v-model.number="age" type="number" />
    
  • .lazy:失去焦点时更新(而非实时更新)
    <!-- 适用于文本区域等不需要实时更新的场景 -->
    <textarea v-model.lazy="article"></textarea>
    
2. 修饰符组合使用
<!-- 输入数字,过滤空格,失去焦点时更新 -->
<input v-model.number.trim.lazy="price" />

四、按键修饰符与系统修饰符

1. 按键修饰符
  • .enter.tab.delete(捕获删除键)等
    <input @keyup.enter="search" />
    
  • 自定义按键修饰符
    // main.js
    Vue.config.keyCodes.f1 = 112; // 定义F1键
    
    <input @keyup.f1="showHelp" />
    
2. 系统修饰符(配合键盘/鼠标按键)
  • .ctrl.shift.alt.meta(Windows键/Command键)
    <button @click.ctrl="copyText">Ctrl+点击复制</button>
    
  • .left.middle.right(鼠标按键)
    <div @click.right="openMenu">右键打开菜单</div>
    

五、组件修饰符(高级场景)

1. .sync 修饰符(Vue 2)
  • 作用:简化父子组件双向绑定,是 v-model 的语法糖
    <!-- 父组件 -->
    <ChildComponent :title.sync="pageTitle" />
    
    <!-- 等价于 -->
    <ChildComponent 
      :title="pageTitle" 
      @update:title="pageTitle = $event" 
    />
    
2. v-model 的修饰符(Vue 2 与 Vue 3)
  • .number.trim.lazy(同表单修饰符)
  • Vue 3 新增 .modelValue 自定义绑定
    <!-- 子组件 -->
    <script setup>
    defineProps({
      modelValue: {
        type: String,
        default: ''
      }
    });
    
    defineEmits(['update:modelValue']);
    </script>
    
    <!-- 父组件 -->
    <ChildComponent v-model="message" />
    

六、问题

1. 问:.prevent 和 .stop 有什么区别?请举例说明。
    • .prevent:阻止事件默认行为(如链接跳转、表单提交);
    • .stop:阻止事件冒泡(如父元素和子元素都有点击事件时,避免同时触发);
    • 示例
      <!-- 阻止链接默认跳转 -->
      <a href="#" @click.prevent="goToPage">点击跳转</a>
      
      <!-- 阻止事件冒泡(子元素点击不触发父元素事件) -->
      <div @click="parentClick">
        <button @click.stop="childClick">点击我</button>
      </div>
      
2. 问:v-model.number 有什么作用?为什么需要它?
    • 作用:将输入值转为数字类型(否则输入框值始终为字符串);
    • 场景:当输入框需要数值计算时(如年龄、价格),避免类型错误:
      <input v-model.number="age" type="number" />
      <button @click="age += 1">+1</button>
      
3. 问:.once 修饰符的实现原理是什么?
    • 本质:为事件添加 { once: true } 选项,使事件监听器只执行一次;
    • Vue 源码中,事件修饰符会被编译为对应原生 API 的参数,.once 对应:
      element.addEventListener('click', handler, { once: true });
      

七、修饰符的底层实现原理

  1. 编译阶段处理
    Vue 模板中的修饰符会被编译为对应的 DOM 事件处理逻辑,例如:

    @click.prevent.stop="handler"
    

    会被编译为:

    event.preventDefault();
    event.stopPropagation();
    handler.call(this, event);
    
  2. 性能优势
    修饰符直接在 DOM 事件层处理,避免 JavaScript 逻辑层的额外判断,提升执行效率。

八、总结

事件修饰符,防默认(.prevent),阻冒泡(.stop),
捕获阶段用 .capture,自身触发加 .self,只一次用 .once;
表单修饰符,.trim 去空格,.number 转数字,.lazy 失焦更;
按键修饰符,.enter .delete,系统修饰符,ctrl shift 配;
组件修饰符,.sync 双向绑,v-model 加修饰,表单更流畅。