在Vue中,组件之间的通信可以有多种方式实现:
-
Props 和 $emit
- Props:父组件向子组件传递数据时,通过属性绑定(
v-bind
或:
)将数据作为属性传给子组件。子组件需要在props选项中声明它接收的属性列表。 - **emit∗∗:子组件向父组件发送事件和数据,通过‘emit**:子组件向父组件发送事件和数据,通过 `emit∗∗:子组件向父组件发送事件和数据,通过‘emit(eventName, payload)
触发自定义事件,并附带数据。父组件可以在使用子组件的地方监听这个事件,通常通过
v-on: eventName或
@eventName` 来实现。
- Props:父组件向子组件传递数据时,通过属性绑定(
-
refs
- refs:直接访问子组件实例或DOM元素。当需要获取子组件的状态或者调用其方法时,可以给子组件添加一个ref引用,在父组件中通过‘this.refs**:直接访问子组件实例或DOM元素。当需要获取子组件的状态或者调用其方法时,可以给子组件添加一个ref引用,在父组件中通过 `this.refs∗∗:直接访问子组件实例或DOM元素。当需要获取子组件的状态或者调用其方法时,可以给子组件添加一个ref引用,在父组件中通过‘this.refs.refName` 访问该子组件实例。
-
Event Bus (全局事件总线)
- 创建一个独立的 Vue 实例作为事件中心,通过它的
$on
和$emit
方法来在任何组件之间发送和接收事件,以此实现跨级或兄弟组件间的通信。
- 创建一个独立的 Vue 实例作为事件中心,通过它的
-
Vuex
- Vuex 是 Vue 提供的状态管理库,用于管理整个应用层级的状态,允许组件间共享状态并通过 actions、mutations 进行状态的变更和同步。
-
依赖注入(provide / inject)
- 父组件可以通过
provide
选项提供数据,而无需显式传递 props,然后在子孙组件中通过inject
选项来注入并使用这些数据。
- 父组件可以通过
-
父子组件通信补充方式
- 使用回调函数作为 Prop,父组件传递一个方法给子组件,子组件在适当的时候调用此方法以更新父组件的状态。
- 使用
v-model
进行双向数据绑定(仅限于表单输入类组件或其他支持 v-model 的自定义组件)。
-
动态组件与 keep-alive 缓存
- 动态组件配合
keep-alive
可以在切换组件时保留状态,并且可以通过激活/停用状态的改变进行间接通信。
- 动态组件配合
Props 和 $emit 父组件
父组件
<template><div><child-component :message="parentMessage" @update-message="handleUpdateMessage"></child-component></div>
</template><script>
import ChildComponent from './ChildComponent.vue'export default {components: { ChildComponent },data() {return {parentMessage: 'Hello from parent'}},methods: {handleUpdateMessage(newMessage) {this.parentMessage = newMessage;}}
}
</script>
子组件
<template><div>{{ message }}<button @click="updateMessage">Update Message</button></div>
</template><script>
export default {props: ['message'],methods: {updateMessage() {this.$emit('update-message', 'New message from child');}}
}
</script>
refs
父组件
<template><div><child-component ref="childRef"></child-component><button @click="callChildMethod">Call Child Method</button></div>
</template><script>
import ChildComponent from './ChildComponent.vue'export default {components: { ChildComponent },methods: {callChildMethod() {this.$refs.childRef.childMethod();}}
}
子组件
<script>
export default {methods: {childMethod() {console.log('Child method called');}}
}
</script>
Event Bus
// eventBus.js
import Vue from 'vue';
export const EventBus = new Vue();// 在任意组件内发送事件
EventBus.$emit('customEvent', payload);// 在任意组件内接收事件
EventBus.$on('customEvent', (payload) => {console.log(payload);
});
Vuex
import Vue from 'vue';
import Vuex from 'vuex';Vue.use(Vuex);export default new Vuex.Store({state: {sharedData: 'Global State'},mutations: {updateSharedData(state, newData) {state.sharedData = newData;}},actions: {updateData({ commit }, newData) {commit('updateSharedData', newData);}},getters: {getSharedData(state) {return state.sharedData;}}
});
组件中使用
<script>
import { mapState, mapActions } from 'vuex';export default {computed: {...mapState(['sharedData'])},methods: {...mapActions(['updateData'])},mounted() {this.updateData('Updated Global State');console.log(this.sharedData);}
};
</script>
provide / inject
父组件
<script>
provide() {return {parentData: 'Provided by Parent'};
}
</script>
子组件
<script>
inject: ['parentData'],
created() {console.log(this.parentData); // "Provided by Parent"
}
</script>
子向父传递
父组件
<template><div><child-component :notifyParent="updateParentData"></child-component><p>Parent Data: {{ parentData }}</p></div>
</template><script>
import ChildComponent from './ChildComponent.vue'export default {components: { ChildComponent },data() {return {parentData: ''}},methods: {updateParentData(newData) {this.parentData = newData;}}
}
</script>
子组件
<template><button @click="callParentMethod">Update Parent Data</button>
</template><script>
export default {props: {notifyParent: { type: Function, required: true }},methods: {callParentMethod() {this.notifyParent('New data from child');}}
}
</script>
v-model 进行双向数据绑定
父组件
<template><input-typeahead v-model="searchText" /><p>Search Text: {{ searchText }}</p>
</template><script>
import InputTypeahead from './InputTypeahead.vue'export default {components: { InputTypeahead },data() {return {searchText: ''}}
}
</script>
子组件
<template><input type="text" :value="value" @input="onInput" />
</template><script>
export default {model: {prop: 'value',event: 'input'},props: {value: String},methods: {onInput(event) {this.$emit('input', event.target.value);}}
}
</script>
动态组件与 keep-alive 缓存进行间接通信
<template><div><button @click="currentTab = 'tab1'">Tab 1</button><button @click="currentTab = 'tab2'">Tab 2</button><keep-alive><component :is="currentTab === 'tab1' ? Tab1 : Tab2" @change-data="handleDataChange" /></keep-alive></div>
</template><script>
import Tab1 from './Tab1.vue';
import Tab2 from './Tab2.vue';export default {components: { Tab1, Tab2 },data() {return {currentTab: 'tab1',sharedData: {}}},methods: {handleDataChange(data) {this.sharedData = data;}}
}
</script>
其中,Tab1 和 Tab2 组件可以通过 $emit
触发 change-data
事件来更新父组件的状态。当切换回已缓存的组件时,由于状态被 keep-alive
保留,可以继续显示上次离开时的数据或状态。