吴旭华 发表于 2024-6-14 22:28:38

前端|Vue Vue3 超具体 实现组件通讯: 父子、子父及兄弟组件间的数据流转

背景:

随着单页面应用(SPA)的流行,前端开发逐渐转向组件化的架构。在这种架构中,应用被分别为多个相互独立、可复用的组件,这些组件须要可以或许高效地相互通讯以协同工作。Vue 3,作为最新版的 Vue.js 框架,通过提供多种组件通讯机制,使得状态管理和数据流变化得更加灵活和高效。
组件间传值的须要往往源于应用的状态管理需求。不同组件大概须要共享同一状态或数据,大概一个组件的举动须要另一个组件做出相应。在这些场景中,确保准确有效的数据流转对于维持应用逻辑的清晰和稳固性至关重要。
一、父组件传值给子组件(Props)

在 Vue 3 中,父组件向子组件传递数据的方式与 Vue 2 类似,通过 props 实现。 
示例:

父组件(ParentComponent.vue):
<template>
<ChildComponent :message="parentMessage" />
</template>

<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const parentMessage = ref('Hello from Parent!');
</script>
 子组件(ChildComponent.vue): 
<template>
<div>{{ message }}</div>
</template>

<script setup>
import { defineProps } from 'vue';

const props = defineProps({
message: String
});
</script>
在 Vue 3 中,我们使用 <script setup> 语法糖,这让组件界说更加简洁。ref 用于界说相应式数据,defineProps 则用于界说组件的 props。
二、子组件传值给父组件(自界说事件)

通过 emit 函数实现了子组件向父组件传值的功能。 
示例:

子组件(ChildComponent.vue):
<template>
<button @click="sendMessageToParent">Send Message to Parent</button>
</template>

<script setup>
import { defineEmits } from 'vue';

const emit = defineEmits(['message-to-parent']);

const sendMessageToParent = () => {
emit('message-to-parent', 'Hello from Child!');
};
</script>
父组件(ParentComponent.vue): 
<template>
<ChildComponent @message-to-parent="receiveMessageFromChild" />
</template>

<script setup>
import { ref } from 'vue';
import ChildComponent from './ChildComponent.vue';

const messageFromChild = ref('');

const receiveMessageFromChild = (message) => {
messageFromChild.value = message;
};
</script>
defineEmits 用于界说组件可以触发的事件。父组件通过 @message-to-parent 监听子组件发出的事件,并在事件发生时实行 receiveMessageFromChild 方法。 
 三、兄弟组件之间传值(提供/注入)

在Vue 3中,provide和inject API确实为非父子关系组件(好比兄弟组件)提供了一种通讯的方式。这种方法通过界说一个可以被后代组件注入的依靠来工作,即使这些组件不是直接的父子关系也可以。
要使用provide和inject实现兄弟组件间的通讯,我们通常须要一个共同的祖先组件来作为数据的“源头”。以下面的组件布局为例:
- 祖先组件(AncestorComponent)
- 父组件(ParentComponent)
    - 子组件 A(ChildComponentA)
    - 子组件 B(ChildComponentB)
这里,我们将在祖先组件中provide一个可以被子组件 A 和 B inject的属性。如果没有共同的直接祖先组件,你可以创建一个空的 Vue 实例大概使用一个全局状态管理库如Vuex 
 1: 设置祖先组件 

首先,我们在祖先组件中provide一个属性。
<!-- AncestorComponent.vue -->
<template>
<ParentComponent />
</template>

<script setup>
import { reactive, provide } from 'vue';
import ParentComponent from './ParentComponent.vue';

// 创建一个响应式对象
const sharedState = reactive({
message: 'Hello from Ancestor!'
});

// 使用 provide 函数来提供这个响应式对象
provide('sharedState', sharedState);
</script>
2: 子组件 A 和 B 注入共享状态 

接下来,我们在子组件 A 和 B 中inject这个属性。
<!-- ChildComponentA.vue -->
<template>
<div>
    <p>Component A: {{ sharedState.message }}</p>
    <button @click="updateMessage">Change Message</button>
</div>
</template>

<script setup>
import { inject } from 'vue';

// 使用 inject 函数来注入 sharedState
const sharedState = inject('sharedState');

const updateMessage = () => {
sharedState.message = 'Updated message from Component A';
};
</script>
<!-- ChildComponentB.vue -->
<template>
<div>Component B: {{ sharedState.message }}</div>
</template>

<script setup>
import { inject } from 'vue';

// 使用 inject 函数来注入 sharedState
const sharedState = inject('sharedState');
</script>
现在,无论是子组件 A 还是 B 任何一个更新了 sharedState.message 的值,另一个组件都会立即反映这个变化,由于它们共享了同一个相应式状态。
3: 父组件作为中介

在某些情况下,我们大概须要一个父组件来作为包含子组件 A 和 B 的容器。
<!-- ParentComponent.vue -->
<template>
<ChildComponentA />
<ChildComponentB />
</template>

<script setup>
import ChildComponentA from './ChildComponentA.vue';
import ChildComponentB from './ChildComponentB.vue';
</script>
这里的 ParentComponent 仅仅作为一个布局容器,现实的状态共享逻辑是在 AncestorComponent 和子组件 A、B 之间通过 provide 和 inject 实现的。这种方法的优点是可以避免使用全局状态管理库,同时仍然可以或许以一种组织精良和可维护的方式共享状态。
四、兄弟组件之间传值(Vuex)

 对于更复杂的状态管理,Vue 3 继续支持 Vuex,一个专为 Vue 应用程序开发的状态管理库。 
示例:

安装 Vuex 4(实用于 Vue 3):
npm install vuex@next --save
创建 Vuex store(store.js):
import { createStore } from 'vuex';

export default createStore({
state() {
    return {
      sharedMessage: 'Initial shared message'
    };
},
mutations: {
    updateSharedMessage(state, newMessage) {
      state.sharedMessage = newMessage;
    }
},
actions: {
    setSharedMessage({ commit }, newMessage) {
      commit('updateSharedMessage', newMessage);
    }
}
});
在主文件中 (main.js) 引入并使用 store:
import { createApp } from 'vue';
import App from './App.vue';
import store from './store';

createApp(App).use(store).mount('#app');
组件 A 更新 Vuex 状态(ComponentA.vue):
<template>
<button @click="updateSharedMessage">Update Shared Message</button>
</template>

<script setup>
import { useStore } from 'vuex';

const store = useStore();

const updateSharedMessage = () => {
store.dispatch('setSharedMessage', 'Message updated by Component A');
};
</script>
组件 B 访问 Vuex 状态(ComponentB.vue):
<template>
<div>Shared message: {{ sharedMessage }}</div>
</template>

<script setup>
import { computed } from 'vue';
import { useStore } from 'vuex';

const store = useStore();
const sharedMessage = computed(() => store.state.sharedMessage);
</script>
在 Vuex 的示例中,ComponentA 通过调用 store.dispatch 方法触发 action 更新 store 中的状态,而 ComponentB 则通过 computed 属性来相应这个状态的变化。
总结

Vue 3 提供了多种组件间通讯的方式,这些方式满意了从简单父子通讯到复杂全局状态管理的各种需求。props 和自界说事件仍然是父子组件通讯的首选方式,provide 和 inject 提供了一种新的兄弟组件通讯方法,而 Vuex 仍然是管理大型应用状态的强盛工具。理解这些通讯机制的实用场景和限定,将资助你构建更加可维护和高效的 Vue 应用。 



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 前端|Vue Vue3 超具体 实现组件通讯: 父子、子父及兄弟组件间的数据流转