在 Vue 中,父子组件之间的数据传递是构建可维护应用的基础。以下是父子组件传值的主要方式,涵盖 Vue 2 和 Vue 3 的通用实践。
一、父组件 → 子组件:通过 Props
这是最标准、最常用的向下传递数据的方式。
1. 父组件传递数据
<!-- ParentComponent.vue -->
<template>
<ChildComponent
:title="parentTitle"
:count="count"
:is-active="isActive"
/>
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
components: { ChildComponent },
data() {
return {
parentTitle: 'Hello from Parent',
count: 10,
isActive: true
}
}
}
</script>
2. 子组件接收并定义 Props
<!-- ChildComponent.vue -->
<template>
<div>
<h2>{{ title }}</h2>
<p>Count: {{ count }}</p>
<p>Active: {{ isActive }}</p>
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
required: true
},
count: {
type: Number,
default: 0
},
isActive: {
type: Boolean,
default: false
}
}
}
</script>
✅ 特点:
- 单向数据流:子组件不能直接修改
props
(会报警告)。- 支持类型校验、默认值、是否必填等。
二、子组件 → 父组件:通过 $emit
触发事件
子组件通过 $emit
触发自定义事件,父组件通过 v-on
监听。
1. 子组件触发事件
<!-- ChildComponent.vue -->
<template>
<button @click="notifyParent">
点击通知父组件
</button>
</template>
<script>
export default {
methods: {
notifyParent() {
// 触发自定义事件,并传递数据
this.$emit('update-count', this.count + 1)
this.$emit('status-change', { active: false, time: Date.now() })
}
}
}
</script>
2. 父组件监听事件
<!-- ParentComponent.vue -->
<template>
<div>
<ChildComponent
@update-count="handleUpdate"
@status-change="handleStatus"
/>
<p>当前计数: {{ count }}</p>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
methods: {
handleUpdate(newCount) {
this.count = newCount
},
handleStatus(payload) {
console.log('状态变更:', payload)
}
}
}
</script>
✅ 特点:
- 实现子到父的“回调”机制。
- 支持传递任意类型的数据。
三、结合 v-model
实现双向绑定(语法糖)
v-model
是 :value
+ @input
的语法糖,常用于表单组件。
1. 父组件使用 v-model
<template>
<CustomInput v-model="message" />
<!-- 等价于 -->
<!-- <CustomInput :modelValue="message" @update:modelValue="message = $event" /> -->
</template>
2. 子组件配合 modelValue
和 update:modelValue
<!-- CustomInput.vue -->
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
<script>
export default {
props: ['modelValue'],
emits: ['update:modelValue'] // 显式声明触发的事件(Vue 3 推荐)
}
</script>
✅ Vue 3 扩展:支持多个
v-model
:<UserEditor v-model:name="userName" v-model:age="userAge" />
四、通过 ref
获取子组件实例(直接访问)
父组件可以通过 ref
直接调用子组件的方法或访问其数据(谨慎使用)。
1. 子组件暴露方法
<!-- ChildComponent.vue -->
<script>
export default {
methods: {
focusInput() {
this.$refs.input?.focus()
}
}
}
</script>
2. 父组件调用子组件方法
<!-- ParentComponent.vue -->
<template>
<ChildComponent ref="childRef" />
<button @click="focusChild">
聚焦子组件输入框
</button>
</template>
<script>
export default {
methods: {
focusChild() {
this.$refs.childRef.focusInput()
}
}
}
</script>
⚠️ 注意:破坏了组件的封装性,应尽量避免,仅用于特定操作(如表单聚焦、动画触发)。
五、使用 .sync
修饰符(Vue 2,Vue 3 已废弃)
Vue 2 中用于实现双向绑定的语法糖(Vue 3 中被 v-model
扩展取代)。
<!-- Vue 2 -->
<ChildComponent :title.sync="parentTitle" />
<!-- 等价于 -->
<ChildComponent
:title="parentTitle"
@update:title="parentTitle = $event"
/>
❌ Vue 3 中已移除
.sync
,推荐使用v-model
或自定义参数的v-model
。
总结:父子传值方式对比
方式 | 方向 | 适用场景 | 推荐指数 |
---|---|---|---|
props | 父 → 子 | 传递配置、数据、状态 | ⭐⭐⭐⭐⭐ |
$emit | 子 → 父 | 子组件通知父组件状态变化 | ⭐⭐⭐⭐⭐ |
v-model | 双向 | 表单组件、需要双向同步的场景 | ⭐⭐⭐⭐ |
ref | 父 → 子(方法调用) | 父组件调用子组件方法 | ⭐⭐(谨慎使用) |
.sync | 双向(Vue 2) | Vue 2 中的双向绑定 | ⭐(Vue 3 已废弃) |
✅ 最佳实践:优先使用
props
+$emit
实现数据流,保持组件的高内聚、低耦合。
THE END