组件通信 props 与 emit
组件拆分后必然面临「父子怎么传数据」。Vue 的标准答案是单向数据流:数据通过 props 从父组件向下传给子组件(子组件只读,不能改);子组件想通知父组件,通过 emit 把事件向上抛,父组件监听事件并处理。数据向下、事件向上,一进一出,关系清清楚楚。
组合式写法里,defineProps({...}) 声明接收的属性(可指定类型、必填、默认值),defineEmits([...]) 声明会抛出的事件,两者在 script setup 里无需 import,编译器自动识别。emit 第二个参数可以携带数据,对应父组件事件处理函数的入参。
常见错误:子组件直接修改 props 的值——Vue 会在控制台警告,因为数据源头在父组件,子组件私改会造成「两头都改、不知道听谁的」。正确做法是要么用 emit 请父组件改,要么用 v-model 语法糖封装。跨多层组件传数据则轮到状态管理(Pinia)出场。
本节要点props 向下传数据(只读),emit 向上抛事件;defineProps/defineEmits 声明接口;子组件不许直接改 props。
代码
<!-- 子组件 Child.vue:props 进,emit 出 -->
<script setup>
// 声明父组件传进来的数据(只读!)
const props = defineProps({
title: { type: String, required: true },
price: { type: Number, default: 0 },
});
// 声明会抛出的事件
const emit = defineEmits(['buy']);
function handleBuy() {
// 通知父组件,并携带数据
emit('buy', props.title);
}
</script>
<template>
<div class="goods">
<span>{{ title }} - ¥{{ price }}</span>
<button @click="handleBuy">购买</button>
</div>
</template>
<!-- 父组件中使用 -->
<!-- <Child title="键盘" :price="199" @buy="(name) => alert('买了' + name)" /> -->
<!-- 记住口诀:数据向下(props)、事件向上(emit) -->



