组件与 Props
父子通信、emit、slot。
35 分钟
组件与 Props
这一课你将能做到
- 拆分父子组件,用 props 向下传数、用
emit向上发事件 - 使用具名/默认 slot 做布局插槽
- 对照 React:props 只读、子通知识父,思想一致、API 不同
为什么要学
单文件越写越长就要拆。拆分后:父管数据与流程,子管展示与局部交互。
本站 React 课同样强调单向数据流;Vue 用 props + emit + slot 表达。
先建立图像
父 ──props──▶ 子
父 ◀──emit─── 子
父在模板里写子标签时,子的 slot 位置被父填内容
| 通道 | 方向 | 人话 |
|---|---|---|
| props | 父→子 | 参数,子只读 |
| emit | 子→父 | 通知父「发生了某事」 |
| slot | 父→子的坑位 | 把模板片段塞进子 |
跟着做
步骤 1:子组件声明 props
<!-- TrackCard.vue -->
<script setup>
const props = defineProps({
title: { type: String, required: true },
level: { type: String, default: "beginner" },
});
</script>
<template>
<article>
<h2>{{ props.title }}</h2>
<p>难度:{{ level }}</p>
</article>
</template>
模板里可直接用 level(setup 已暴露)。defineProps 是编译期宏,无需 import。
步骤 2:父传入
<script setup>
import TrackCard from "./TrackCard.vue";
</script>
<template>
<TrackCard title="Vue 3 核心" level="intermediate" />
</template>
步骤 3:子 emit,父处理
<!-- CounterBtn.vue -->
<script setup>
const emit = defineEmits(["inc"]);
</script>
<template>
<button type="button" @click="emit('inc', 1)">加一</button>
</template>
<script setup>
import { ref } from "vue";
import CounterBtn from "./CounterBtn.vue";
const total = ref(0);
</script>
<template>
<p>{{ total }}</p>
<CounterBtn @inc="(n) => (total += n)" />
</template>
注意:模板里 total 是 ref 自动解包,total += n 可行;在纯 script 回调里记得 .value。
步骤 4:默认 slot
<!-- Panel.vue -->
<template>
<section class="panel">
<slot>默认内容</slot>
</section>
</template>
<Panel>
<p>侧栏说明</p>
</Panel>