在 Vue3 中,组件是构建应用的基本单元。
组件之间的通信主要分为:
- **父 → 子**:通过 Props 传递数据
- **子 → 父**:通过 Emit 触发事件
----------
一、父向子通信:Props
基本用法
<!-- 父组件 -->
<UserCard name="Alice" age="25" />
<!-- 子组件 UserCard.vue -->
<template>
<div>
<h3>{{ name }}({{ age }} 岁)</h3>
</div>
</template>
<script setup>
defineProps({
name: String,
age: Number
})
</script>
动态传递
<!-- 父组件 -->
<UserCard :name="username" :age="userage" />
<script setup>
const username = 'Jack'
const userage = 30
</script>
二、子向父通信:Emit
基本用法
<!-- 子组件 MyButton.vue -->
<template>
<button @click="$emit('custom-click', '来自子组件的数据')">
点击我
</button>
</template>
<script setup>
defineEmits(['custom-click'])
</script>
<!-- 父组件 -->
<MyButton @custom-click="handleClick" />
<script setup>
function handleClick(data) {
console.log('父组件收到:', data)
}
</script>
三、Props 与 Emit 结合示例
做一个简单的计数器组件,父组件传入初始值,子组件点击按钮修改并通知父组件。
Counter.vue(子组件)
<template>
<div>
<p>当前计数:{{ count }}</p>
<button @click="increment">+1</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const props = defineProps({
modelValue: Number
})
const emit = defineEmits(['update:modelValue'])
const count = ref(props.modelValue)
function increment() {
count.value++
emit('update:modelValue', count.value) // 通知父组件更新
}
</script>
App.vue(父组件)
<template>
<Counter v-model="num" />
<p>父组件同步的值:{{ num }}</p>
</template>
<script setup>
import { ref } from 'vue'
import Counter from './Counter.vue'
const num = ref(0)
</script>
四、注意事项
-
Props 是单向数据流
-
子组件不能直接修改 Props
-
如果需要修改,先拷贝到本地变量,或通过 Emit 通知父组件更新
-
-
Emit 事件命名
-
建议用小写加中划线(如
custom-click),符合 Vue 事件命名规范 -
update:modelValue是 v-model 的默认事件
-
五、实战小项目:Todo 列表组件化拆分
父组件管理任务数据,子组件负责渲染任务和触发完成事件。
TodoItem.vue
<template>
<li>
{{ todo.text }}
<button @click="$emit('done', todo.id)">完成</button>
</li>
</template>
<script setup>
defineProps({
todo: Object
})
defineEmits(['done'])
</script>
App.vue
<template>
<ul>
<TodoItem
v-for="t in todos"
:key="t.id"
:todo="t"
@done="markDone"
/>
</ul>
</template>
<script setup>
import { ref } from 'vue'
import TodoItem from './TodoItem.vue'
const todos = ref([
{ id: 1, text: '学习 Vue3', done: false },
{ id: 2, text: '写一篇文章', done: false }
])
function markDone(id) {
todos.value = todos.value.filter(t => t.id !== id)
}
</script>
小结
-
Props → 父传子(数据单向流动)
-
Emit → 子传父(事件通知)
-
结合 v-model 可以实现双向绑定
-
组件拆分能让代码更可维护、更可复用
1894

被折叠的 条评论
为什么被折叠?



