.vue中.native修饰符使父组件监听子组件根元素原生事件,.sync修饰符是语法糖,等价于:prop加@update:prop,二者均依赖子组件主动$emit,但.native不涉及数据回传,.sync用于prop双向更新。

Vue 中带有修饰符的自定义事件,本质仍是 $emit 触发的事件,但修饰符(如 .native、.sync、.capture 等)作用对象不同,需明确“谁在监听”“谁在触发”“修饰符挂在哪一层”。处理子组件向父组件回传数据时,只有 .native 和 .sync 与自定义事件直接相关,且使用场景和逻辑完全不同。
.native 修饰符:让原生事件穿透到子组件根元素
适用场景:父组件想监听子组件根元素上的原生 DOM 事件(比如 click、input),但子组件模板里没显式绑定该事件。
- 子组件
<template></template>根节点是一个<div> 或 <code><button></button>,它天然支持click; - 父组件直接写
@click="handle"不会生效(因为@click默认监听的是子组件自定义事件,不是原生事件); - 加
.native后,Vue 就把该监听器绑定到子组件的根 DOM 元素上。
<!-- 父组件 --> <childcomponent></childcomponent>
<!-- 子组件 --> <template><div>我是子组件根元素</div> </template>
✅ 此时点击子组件区域,会触发父组件的 onRootClick。
⚠️ 注意:这不是子组件主动 $emit 的自定义事件,而是原生事件冒泡捕获;不涉及子组件内部逻辑主动回传数据。若需传参,仍要靠子组件自己 $emit。
.sync 修饰符:语法糖,简化「prop 更新 + 事件触发」组合
适用场景:父组件传一个 prop(如 value),子组件需要“更新它”,但不能直接改 prop —— 应通过 $emit('update:xxx', newVal) 通知父组件。
.sync 是 Vue 2 的语法糖(Vue 3 中被 v-model 取代),自动帮你展开成:
<!-- 父组件写法 --> <childcomponent :title.sync="pageTitle"></childcomponent>
等价于:
<childcomponent :title="pageTitle"></childcomponent>
子组件内部只需:
this.$emit('update:title', '新标题')
✅ 父组件 pageTitle 自动更新,语义清晰、代码简洁。
✅ 支持任意 prop 名,只要事件名是 update:xxx。
✅ 一次 .sync 对应一个 prop,多个用多个(如 :name.sync="a" :age.sync="b")。
v-model:更现代、更灵活的双向绑定封装
Vue 2.2+ 推荐用 v-model 替代 .sync(尤其表单类组件)。默认监听 input 事件:
<!-- 父组件 --> <custominput v-model="searchText"></custominput>
等价于:
<custominput :value="searchText"></custominput>
子组件:
export default {
props: ['value'], // 必须叫 value 才能匹配默认 v-model
methods: {
handleChange(val) {
this.$emit('input', val) // 触发 input 事件,父组件自动接收
}
}
}
Vue 3 中升级为 modelValue + update:modelValue,还支持自定义 v-model 的 prop 名和事件名:
<!-- Vue 3 --> <customswitch v-model:checked="isActive"></customswitch>
子组件需声明:
props: { checked: Boolean },
emits: ['update:checked'],
setup(props, { emit }) {
const toggle = () => emit('update:checked', !props.checked)
}
常见错误与避坑要点
-
.native不能和自定义事件混用:@submit.native是监听子组件根元素的原生submit,不是你$emit('submit')的事件。 -
.sync和v-model都要求子组件主动$emit对应事件,否则父组件不会更新。 - 事件名拼写必须完全一致(包括大小写、短横线):
$emit('update-name')≠@update:name(后者正确,前者错)。 - 不要在子组件
mounted里$emit初始化值——此时父组件可能还没准备好监听器,建议用$nextTick或延后触发。
不复杂但容易忽略。











