Bootstrap

Vue3组件之间的通信

        在 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>

;