Vue 3 组件通信:深入理解 Props 和 Emits 的使用与最佳实践
Vue 3 中的 props
和 emits
是组件通信的基础,它们允许组件之间的数据流动和事件触发。以下是 Vue 3 中 props
和 emits
的详细知识点:
Props
一. 基础用法
在Vue中,props
是父组件传递给子组件的数据。以下是在父组件中定义和传递 props
的步骤:
1. 定义子组件
首先,你需要有一个子组件,它声明了它期望接收的 props
。
<!-- ChildComponent.vue -->
<template>
<div>{{ message }}</div>
</template>
<script>
export default {
props: {
message: String
}
}
</script>
2. 在父组件中使用子组件
然后,在父组件中,你可以像使用HTML元素一样使用这个子组件,并传递 props
。
<!-- ParentComponent.vue -->
<template>
<ChildComponent :message="parentMessage" />
</template>
<script>
import ChildComponent from './ChildComponent.vue';
export default {
components: {
ChildComponent
},
data() {
return {
parentMessage: 'Hello from parent!'
}
}
}
</script>
3. 使用 v-bind
传递 props
你可以使用 v-bind
指令(简写为冒号 :
)来动态传递数据作为 props
。
<ChildComponent :propA="valueA" :propB="valueB" />
4. 使用字面量值传递 props
你也可以直接传递字面量值作为 props
。
<ChildComponent :count="10" />
5. 使用计算属性传递 props
你可以使用计算属性的结果作为 props
。
<template>
<ChildComponent :filteredList="computedList" />
</template>
<script>
export default {
data() {
return {
items: ['item1', 'item2', 'item3']
}
},
computed: {
computedList() {
return this.items.filter(item => item.includes('2'));
}
}
}
</script>
6. 使用方法返回值传递 props
你可以使用方法的返回值作为 props
。
<template>
<ChildComponent :user="getUserName" />
</template>
<script>
export default {
methods: {
getUserName() {
return 'Kimi';
}
}
}
</script>
7. 使用插槽插槽传递 props
有时候,你可能会通过插槽的内容传递 props
。
<template>
<ChildComponent>
<template v-slot="{ propA }">
<div>{{ propA }}</div>
</template>
</ChildComponent>
</template>
在父组件中定义 props
的关键在于理解 props
是单向数据流,即它们只能从父组件流向子组件,而不能反过来。这有助于保持组件之间的数据隔离和组件的可重用性。
二. 类型检查和验证
Vue 3 支持对 props
进行类型检查和验证,确保数据的正确性。
<script>
export default {
props: {
// 基础类型检查
propA: Number,
// 对象类型检查
propB: {
type: Object,
default: () => ({ x: 0, y: 0 })
},
// 带有验证函数的 prop
propC: {
type: String,
validator: value => {
return ['small', 'medium', 'large'].includes(value);
}
}
}
}
</script>
三. 默认值
你可以为 props
提供默认值,以便在没有提供值时使用。
<script>
export default {
props: {
propA: {
type: String,
default: 'default value'
}
}
}
</script>
四. 非响应式 Props
props
是非响应式的,这意味着如果你更改了 props
的值,Vue 不会更新 DOM。如果你需要响应式数据,应该使用局部数据。
Emits
1. 基础用法
emits
选项用于定义组件可以触发的事件。在子组件中,你可以使用 this.$emit
来触发这些事件。
// 子组件
<script>
export default {
emits: ['update'],
methods: {
updateValue() {
this.$emit('update', 'new value');
}
}
}
</script>
在父组件中,你可以监听这些事件:
<!-- 父组件 -->
<template>
<ChildComponent @update="handleUpdate" />
</template>
<script>
export default {
methods: {
handleUpdate(value) {
console.log(value); // 'new value'
}
}
}
</script>
2. 事件修饰符
Vue 3 支持事件修饰符,如 .stop
、.prevent
和 .once
,这些修饰符可以在监听事件时直接使用。
<!-- 父组件 -->
<template>
<ChildComponent @update.stop="handleUpdate" />
</template>
3. 事件参数
你可以在触发事件时传递参数,这些参数可以在父组件中接收。
// 子组件
<script>
export default {
emits: ['custom-event'],
methods: {
triggerCustomEvent() {
this.$emit('custom-event', { key: 'value' });
}
}
}
</script>
在父组件中:
<!-- 父组件 -->
<template>
<ChildComponent @custom-event="handleCustomEvent" />
</template>
<script>
export default {
methods: {
handleCustomEvent(payload) {
console.log(payload); // { key: 'value' }
}
}
}
</script>
在 <script setup>
中使用 Props 和 Emits
Vue 3 引入了 <script setup>
语法糖,使得 props
和 emits
的声明更加简洁。
1. defineProps 和 defineEmits
<script setup>
import { defineProps, defineEmits } from 'vue';
// 声明 props
const props = defineProps({
propA: String,
propB: Number
});
// 声明 emits
const emit = defineEmits(['update', 'custom-event']);
// 触发事件
function updateValue() {
emit('update', 'new value');
}
</script>
2. withDefaults
<script setup>
import { withDefaults } from 'vue';
// 声明并设置默认值
const props = withDefaults(defineProps<{
propA?: string;
propB?: number;
}>(), {
propA: 'default string',
propB: 100
});
</script>
3. 类型定义
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue';
// 使用 TypeScript 定义 props 和 emits 类型
const props = defineProps<{
propA: string;
propB?: number;
}>();
const emit = defineEmits<{
(e: 'update', value: string): void;
(e: 'custom-event', payload: { key: string }): void;
}>();
</script>
通过这些知识点,你可以在 Vue 3 中灵活地使用 props
和 emits
来构建组件化的应用。