Vue 常用修饰符大全
Vue 修饰符是写在指令之后、以点号连接的特殊后缀。它们可以改变事件监听、表单同步或属性绑定的细节。
原文的
.lazy、.trim、.number、事件修饰符和.sync介绍大部分有基础价值,但存在两个明显错误:把.sync多处写成了async,把.passive错误地解释成滚动事件的.lazy。本文同时补充 Vue 2.7 与 Vue 3.5 的迁移边界。
一、修饰符分为哪些类型
常见修饰符可以按用途分为:
- 表单
v-model修饰符:.lazy、.trim、.number; - DOM 事件修饰符:
.stop、.prevent、.self、.capture、.once、.passive; - 系统按键修饰符:
.ctrl、.alt、.shift、.meta、.exact; - 键盘按键修饰符:
.enter、.tab、.delete、.esc、.space、.up、.down、.left、.right以及 kebab-case 按键名; - 鼠标按键修饰符:
.left、.right、.middle; v-bind修饰符:.prop、.camel、Vue 3 的.attr;- Vue 2 组件兼容写法:
.native、.sync,它们在 Vue 3 中有迁移替代方案。
修饰符不是都在做同一种事情:.stop 和 .prevent 是事件处理逻辑,.once、.capture、.passive 会影响监听器选项,.enter 和 .ctrl 则是事件过滤条件。
二、表单 v-model 修饰符
1. .lazy
默认情况下,文本输入框的 v-model 在每次 input 事件后同步数据。.lazy 会改为在 change 事件后同步:
<template>
<input v-model.lazy="description" />
<p>{{ description }}</p>
</template>
.lazy 只改变同步时机,不是异步加载,也不是事件监听器的 passive 选项。
2. .trim
.trim 会去掉输入字符串两端的空白:
<input v-model.trim="name" />
它适合用户名、搜索关键字等文本输入。是否应该自动去除空格仍然取决于业务;密码、代码或需要保留空格的文本不应盲目使用。
3. .number
.number 尝试将输入转换成数字:
<input v-model.number="age" type="number" />
如果转换失败,Vue 会保留原始字符串;空输入也可能得到空字符串。不要只根据 HTML 的 type="number" 就假设后端一定会收到 number,提交前仍应进行类型校验。
Vue 3 对 type="number" 的原生输入会自动应用 number 行为,但显式写出 .number 更容易表达意图。
三、DOM 事件修饰符
1. .stop
调用 event.stopPropagation(),阻止事件继续向父元素传播:
<div @click="say('parent')">
<button @click.stop="say('button')">点击</button>
</div>
点击按钮时,按钮处理器执行,但事件不会继续冒泡到父级 div。.stop 不会阻止默认行为。
2. .prevent
调用 event.preventDefault(),阻止浏览器默认行为:
<form @submit.prevent="submitForm">
<button type="submit">提交</button>
</form>
.prevent 不会阻止冒泡;如果同时需要阻止冒泡,应另加 .stop。
3. .self
只有当事件的 target 就是当前元素自身时才执行:
<div @click.self="closePanel">
<button>点击按钮不会触发 closePanel</button>
</div>
.self 不是“阻止事件冒泡”的另一种写法,而是过滤事件目标。子元素事件即使冒泡到当前元素,也不会通过 self 判断。
修饰符顺序会影响生成代码的顺序:
<!-- 先 prevent,再 self:子元素点击也可能被阻止默认行为 -->
<div @click.prevent.self="handle"></div>
<!-- 先判断 self,再 prevent:只处理元素自身点击的默认行为 -->
<div @click.self.prevent="handle"></div>
4. .once
监听器只执行一次:
<button @click.once="submitOnce">只提交一次</button>
.once 也可以用于组件事件,但它只控制监听器次数,不会让组件实例只创建一次。
5. .capture
使用事件捕获阶段监听。捕获阶段从外层向目标元素传播,目标和冒泡阶段则相反:
<div @click.capture="log('outer-capture')">
<div @click.capture="log('middle-capture')">
<button @click="log('button')">点击</button>
</div>
</div>
典型顺序是外层捕获、内层捕获、目标处理,然后进入冒泡阶段。实际顺序还会受到 stopPropagation 和其他监听器的影响。
6. .passive
.passive 会以 passive: true 的选项注册事件监听器,告诉浏览器该监听器不会调用 preventDefault():
<div class="scroll-area" @scroll.passive="onScroll">
<!-- ... -->
</div>
它的作用不是 .lazy,也不是让 onscroll “延迟触发”。在触摸、滚动等浏览器默认行为场景中,浏览器可以更早执行滚动,而不必等待监听器确认是否阻止默认行为。
不要同时使用 .passive 和 .prevent: passive 监听器已经声明不会阻止默认行为,浏览器会忽略或警告 preventDefault()。
7. .native:仅 Vue 2 组件兼容写法
Vue 2 中,组件上的普通 @click 默认监听组件自定义事件;.native 可以把监听器绑定到组件根元素:
<!-- Vue 2.7 -->
<base-input @focus.native="handleFocus" />
它依赖组件有合适的单一根元素。如果组件根节点改变成 label 或多层结构,监听行为可能与预期不符。
Vue 3 已移除 .native。Vue 3 中应直接使用组件事件和 $emit/emit:
<!-- Child.vue,Vue 3 -->
<script setup lang="ts">
const emit = defineEmits<{
focus: []
}>()
</script>
<template>
<input @focus="emit('focus')" />
</template>
<!-- Parent.vue -->
<Child @focus="handleFocus" />
如果 Vue 3 子组件没有声明某个事件,单根组件上的监听器可能按照 fallthrough 规则进入根元素;如果在 emits 中声明了该事件,它表示监听子组件显式触发的组件事件。多根组件需要显式处理 $attrs。
参考:Vue 3 .native 移除、Fallthrough Attributes。
四、鼠标按键修饰符
Vue 提供:
.left:主指针按钮,通常是鼠标左键;.right:次指针按钮,通常是鼠标右键;.middle:辅助指针按钮,通常是鼠标中键。
<button @click.left="handleLeft">主按钮</button>
<button @click.right="handleRight">次按钮</button>
<button @click.middle="handleMiddle">辅助按钮</button>
不同浏览器和事件类型的 button 映射可能不同。Vue 2 编译器会对 click.right、click.middle 做事件类型转换;Vue 3 运行时主要通过 MouseEvent.button 判断。对于复杂指针交互,可以直接读取事件对象。
五、键盘修饰符
1. 按键别名
<input @keyup.enter="submit" />
<input @keyup.esc="closeDialog" />
<input @keyup.page-down="handlePageDown" />
常见别名包括:
.enter.tab.delete(同时覆盖 Delete 和 Backspace).esc.space.up、.down、.left、.right
Vue 3 支持使用 KeyboardEvent.key 对应的 kebab-case 名称,例如 page-down。
2. 系统修饰键
<!-- Ctrl/Command + Enter 才触发 -->
<textarea @keydown.ctrl.enter="submit" />
<!-- 必须只有 Ctrl/Command,没有其他系统键 -->
<input @keyup.ctrl.exact="handleCtrlOnly" />
系统修饰键包括:
.ctrl.alt.shift.meta(macOS Command、Windows 键等).exact
.exact 要求事件只包含指定的系统修饰键,不会阻止普通字符键本身。
3. keyCode 的版本边界
原文中的:
<!-- 不要把 keyCode 当作 Vue 3 当前写法 -->
<input @keyup.keyCode="shout" />
这不是正确的通用语法。Vue 2 时代可以使用数字 keyCode,例如:
<!-- Vue 2 历史写法:13 表示 Enter -->
<input @keyup.13="submit" />
也可以在 Vue 2 中配置 Vue.config.keyCodes 自定义别名。Vue 3 已移除数字 keyCode modifier 和 config.keyCodes,推荐使用按键别名或直接读取 event.key:
<input @keyup="handleKeyup" />
function handleKeyup(event: KeyboardEvent) {
if (event.key === 'Enter') {
submit()
}
}
六、系统修饰键与事件顺序示例
修饰符可以组合使用:
<!-- Ctrl/Command + 点击,并且阻止默认行为 -->
<a href="/settings" @click.ctrl.prevent="openSettings">
设置
</a>
要注意操作系统和浏览器差异:
- macOS 常用
.meta表示 Command; - Windows/Linux 常用
.ctrl表示 Ctrl; - 触摸设备不一定产生传统鼠标按键事件;
- 复杂键盘布局不要只依赖 keyCode,优先使用
event.key或event.code。
七、v-bind 修饰符
1. .prop
.prop 强制把值设置为 DOM property,而不是 HTML attribute:
<input :value.prop="value" />
它不是用来“隐藏数据”或“避免污染 HTML”的。property 和 attribute 是浏览器中不同的概念:
- attribute 是 HTML 标签上的特性;
- property 是 DOM 对象上的 JavaScript 属性;
- Vue 3 通常会根据元素和属性自动选择合适的绑定方式;
- 只有在需要明确控制时才使用
.prop或.attr。
2. .camel
.camel 将连字符属性转成 camelCase,主要用于 in-DOM 模板或 SVG 属性名:
<!-- 需要把 view-box 绑定成 viewBox -->
<svg :view-box.camel="viewBox"></svg>
在 SFC 预编译模板中,编译器通常可以直接保留正确的大小写,因此很多场景不需要 .camel。原文的 view-Box 和 :viewBox 示例没有真正展示该 modifier,应以 :view-box.camel 为准。
3. .attr(Vue 3)
Vue 3 支持 .attr,用于强制设置 HTML attribute:
<div :aria-label.attr="label"></div>
具体元素属性在 Vue 中有默认判断逻辑,.prop 和 .attr 适合需要明确指定行为的场景。
八、.sync:Vue 2 与 Vue 3 的迁移
原文把 .sync 多处写成了 async。Vue 没有通用的 v-bind.async,正确名称是 .sync。
Vue 2.7
<Child :title.sync="pageTitle" />
它大致等价于:
<Child
:title="pageTitle"
@update:title="pageTitle = $event"
/>
子组件需要发出对应事件:
this.$emit('update:title', newTitle)
使用 .sync 时:
- 事件名必须是
update:<propName>; <propName>必须与绑定的 prop 名一致;- 它不是任意 prop 的双向绑定;
- 不要把
.sync和复杂表达式混在一起; - 在字面量对象上使用
v-bind.sync容易产生难以理解的行为,应拆成明确 prop。
Vue 3.5
Vue 3 移除了 .sync,使用带参数的 v-model:
<Child v-model:title="pageTitle" />
子组件声明 prop 并触发 update:title:
<script setup lang="ts">
const props = defineProps<{
title: string
}>()
const emit = defineEmits<{
'update:title': [value: string]
}>()
function updateTitle(value: string) {
emit('update:title', value)
}
</script>
Vue 3.4+(Vue 3.5.39 可用)还可以使用 defineModel:
<script setup lang="ts">
const title = defineModel<string>('title', {
required: true,
})
</script>
<template>
<input v-model="title" />
</template>
参考:Vue 3 Component v-model、Vue 3 v-model 迁移。
九、组件 v-model 的修饰符与版本差异
Vue 2 默认协议
<LegacyInput v-model="title" />
默认相当于:
<LegacyInput
:value="title"
@input="title = $event"
/>
Vue 2 可以通过 model 选项改变 prop 和事件名:
export default {
model: {
prop: 'checked',
event: 'change',
},
props: {
checked: Boolean,
},
}
Vue 3 默认协议
<ModernInput v-model="title" />
默认相当于:
<ModernInput
:modelValue="title"
@update:modelValue="title = $event"
/>
多个模型可以写成:
<Editor
v-model:title="title"
v-model:content="content"
/>
.trim、.number 等组件模型修饰符需要由子组件显式决定如何处理;在 Vue 3.4+ 可以使用 defineModel 的第二个返回值或 get/set 选项实现自定义转换。
十、常见修饰符对照表
| 修饰符 | Vue 2.7.16 | Vue 3.5.39 | 作用/迁移说明 |
|---|---|---|---|
.lazy | 支持 | 支持 | v-model 在 change 时同步 |
.trim | 支持 | 支持 | 去除两端空白 |
.number | 支持 | 支持 | 尝试转换为 number |
.stop | 支持 | 支持 | 阻止冒泡 |
.prevent | 支持 | 支持 | 阻止默认行为 |
.self | 支持 | 支持 | 只处理 target 为自身的事件 |
.capture | 支持 | 支持 | 捕获阶段监听 |
.once | 支持 | 支持 | 监听器只执行一次 |
.passive | 支持 | 支持 | passive: true,不能与 prevent 同用 |
.left/.right/.middle | 支持 | 支持 | 鼠标按钮过滤 |
.enter 等按键别名 | 支持 | 支持 | 推荐写法 |
| 数字 keyCode | 历史支持 | 移除 | Vue 3 使用按键名或 event.key |
.ctrl/.alt/.shift/.meta | 支持 | 支持 | 系统修饰键 |
.exact | 支持 | 支持 | 限制系统修饰键组合 |
.prop | 支持 | 支持 | 强制 DOM property |
.camel | 支持 | 支持 | 属性名大小写转换 |
.attr | 不作为常用 2.x API | 支持 | 强制 HTML attribute |
.native | 支持组件根原生事件 | 移除 | Vue 3 使用 emits/fallthrough |
.sync | 支持 2.3+ | 移除 | Vue 3 使用 v-model:prop |
十一、实际使用建议
- 修饰符顺序会改变生成代码顺序,
self、prevent、stop组合时要读懂语义; .passive与.prevent不要同时使用;- Vue 3 新代码不要使用
.native、数字 keyCode 和.sync; - 组件事件应通过
defineEmits/$emit明确声明; - 不要用
.prop代替数据安全或属性校验; v-model修饰符只解决同步和转换细节,表单校验仍需单独处理;- 对键盘无障碍交互,不要只监听鼠标事件,也不要只依赖数字 keyCode;
- 复杂滚动监听需要考虑节流、
requestAnimationFrame和 passive,而不仅仅是添加.passive。
十二、总结
.lazy、.trim、.number是表单v-model修饰符;.stop阻止冒泡,.prevent阻止默认行为,.self过滤事件目标;.once、.capture、.passive影响监听器行为,其中.passive不是.lazy;.enter等按键别名比数字 keyCode 更可靠,Vue 3 已移除数字 keyCode;.prop操作 DOM property,.attr操作 HTML attribute,.camel处理属性命名;- Vue 2 的
.native、.sync需要单列为历史边界,Vue 3 分别使用事件 fallthrough/emits和v-model:prop; - 修饰符只是语法辅助,事件传播、浏览器默认行为、组件 emits 和 DOM property/attribute 的概念仍要分别理解。
官方参考
Vue 2
Vue 3
- Vue 3 事件处理
- Vue 3 表单输入绑定
- Vue 3 组件事件
- Vue 3 Fallthrough Attributes
- Vue 3 Built-in
v-bind - Vue 3 Component
v-model - Vue 3
.native迁移 - Vue 3 keyCode 迁移
- Vue 3
v-model迁移
原文出处
作者:CoderBin
来源:稀土掘金
本文保留原文的常见修饰符总结,并补充 Vue 2.7.16 与 Vue 3.5.39 的 API 版本边界。