在 Vue 3 中,组件通信是构建应用程序时必须处理的核心问题之一。有效的组件通信可以帮助我们组织和管理应用程序的状态和行为,使得代码更加清晰和可维护。
Vue 3 提供了多种方式来实现组件之间的通信,每种方式都有其适用的场景。在本文中,博主将详细介绍 Vue 3 中常用的几种组件通信方式及其使用方法。
1.Props
按照官方的话来说,我们需要先在组件上 显式的声明Props ,这样 Vue 才知道我们传递的哪些是 Props ,哪些是 透传 ( Attribute ) 。
所谓 透传(Attribute),其实就是指传递给组件,又没有被声明成 Props、$emit 的属性 或 v-on 的事件监听器。详细信息请参考 Vue.js官方文档
在子组件 (ChildComponent.vue) 中,我们可以通过Props声明属性:
<!-- 子组件 ChildComponent.vue -->
<template>
<div>
<p>{{ props.orderInfo }}</p>
</div>
</template>
<script setup>
const props = defineProps({
orderInfo: {
type: object,
default: () => {}
}
})
</script>
在父组件中,我们可以通过为子组件 (ChildComponent.vue) 绑定属性 的方式,将参数传递给子组件 (ChildComponent.vue) 的 Props 。
<!-- 父组件 FatherComponent.vue -->
<tamplate>
<!-- 对于传递 props 来说,使用 camelCase 并没有太多优势,因此官方更推荐 pascal-case 的形式 -->
<ChildComponent :order-info="state.orderForm"><ChildComponent>
</tamplate>
<script setup>
import { reactive } from 'vue'
const state = reactive({
orderForm: {
orderId: '123456',
orderName: 'Test',
sumPrice: 50
}
})
</script>
最后,父组件 传递给 子组件 的 orderForm 就可以通过 插值表达式 在子组件中显示出来
2.事件 ( $emit )
在 子组件 (ChildComponent.vue) 中,我们可以通过 $emit 方法触发一个自定义事件,并向父组件传递需要的参数。
<!-- 子组件 ChildComponent.vue -->
<tamplate>
<button @click="handleClick"></button>
</tamplate>
<script setup>
import { ref } from 'vue'
const status = ref('Success')
const emit = defineEmits(['refresh']);
const handleClick = () => {
emit('refresh')
}
</script>
父组件可以通过在子组件上使用 v-on
或者简写形式 @
来监听 子组件 发出的事件,并在事件处理函数中接收传递的参数。
<!-- 父组件 FatherComponent.vue -->
<tamplate>
<ChildComponent @refresh="callback"></ChildComponent>
<tamplate>
<script setup>
const callback = (value) => {
console.log(value)
}
</script>
以上两种组件通信方式为单向数据流,非常适合简单的数据传递需求
3.Pinia
Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态(数据) 。
这里先假设已经在项目中已经引入了 Pinia,如果不知道怎么安装Pinia,请参考 Vue项目安装Pinia
/*
* orderStore.js
* 首先,我们定义一个store。 ==> 这里博主采用组合式API写法
*/
import { defineStore } from 'pinia'
import { ref } from 'vue'
// 这里,第一个参数是你的应用中 Store 的唯一 ID。==> 我的是 orderInfo
export const useOrderStore = defineStore('orderInfo', () => {
// 可以在任意组件中访问 orderInfo 变量
const orderInfo = ref()
const setOrderInfo = (data) => {
orderInfo.value = data
}
const getOrderInfo = () => {
return orderInfo.value
}
return { orderInfo, setOrderInfo, getOrderInfo }
})
然后,在 A 组件 中引入 orderStore.js ,并通过函数调用的方式使用Pinia
<!-- A 组件中 OnceComponent.vue -->
<tamplate>
<button @click="handleClick"> Click </button>
</tamplate>
<script setup>
import { reactive } from 'vue'
import { useOrderStore } from '/@/stores/orderInfo'
const state = reactive({
orderForm: {
orderId: '123456',
orderName: 'Test',
sumPrice: 50
}
})
// 通过点击事件将数据(状态)存储到 pinia 中
const handleClick = () => {
useOrderStore().setOrderInfo(state.orderForm);
}
</script>
最后,在 B 组件 中,通过同样的方式从 Pinia 中获取到 A 组件 存储的数据:
<!-- B 组件中 TwoComponent.vue -->
<tamplate>
<p>{{ state.orderForm }}</p>
</tamplate>
<script setup>
import { reactive } from 'vue'
import { useOrderStore } from '/@/stores/orderInfo'
const state = reactive({
// 直接将 pinia 中的 orderInfo 赋值给 orderForm
orderForm: useOrderStore().getOrderInfo()
})
</script>