详解Vue组件通讯的原理和方法

一、Vue组件通讯基本概念

在Vue中,组件是拆分应用的基本单位,一个组件通常包括HTML模板、JavaScript脚本以及CSS样式等内容。组件之间的通讯是Vue应用中非常重要的一个点,因此,掌握Vue组件通讯的原理和方法是非常必要的。

1. 父子组件通讯

父子组件通讯是根据组件树结构实现的。父组件通过props向子组件传递数据,子组件通过发射事件$emit来通知父组件数据的变化。

//父组件

<template>

<div>

<HelloWorld :parent-msg="msg" @childMsg="getChildData"></HelloWorld>

</div>

</template>

<script>

import HelloWorld from './components/HelloWorld.vue';//导入子组件

export default {

components: {

HelloWorld,

},

data() {

return {

msg: '来自父组件的数据',

};

},

methods: {

getChildData(res) {

console.log(res)

}

}

};

</script>

//子组件

<template>

<div>

<p><strong>子组件接收到的来自父组件的数据:{{ parentMsg }}</strong></p>

<button @click="emitChildData">通知父组件</button>

</div>

</template>

<script>

export default {

props: {

parentMsg: {

type: String,

default: '',

},

},

methods: {

emitChildData() {

this.$emit('childMsg', '子组件发起事件');

},

},

};

</script>

2. 兄弟组件通讯

兄弟组件通讯需要通过共同的父组件作为桥梁,父组件通过provide/inject方式提供一个数据实例,兄弟组件可以通过在inject中获取这个实例,并监听它的变化。

//父组件

<template>

<div>

<Header></Header>

<Sidebar></Sidebar>

<Content :contentData="contentData"></Content>

</div>

</template>

<script>

import Header from './components/Header.vue';//导入兄弟组件

import Sidebar from './components/Sidebar.vue';

import providerData from './mixins/provideData';//导入provide/inject实例

export default {

components: {

Header,

Sidebar,

},

mixins: [providerData],//mixin中提供共享数据实例

data() {

return {

contentData: '',

};

},

};

</script>

//Header.vue

<template>

<div>

<p><strong>Header组件接收到的如果要与Sidebar组件同步的数据:{{ nowData }}</strong></p>

</div>

</template>

<script>

export default {

inject: ['provider'],//从父组件提供的provide注入数据实例

data() {

return {

nowData: this.provider,

};

},

mounted() {

this.$watch('provider', newVal => {

this.nowData = newVal;

});

},

};

</script>

//Sidebar.vue

<template>

<div>

<p><strong>Sidebar组件接收到的如果要与Header组件同步的数据:{{ sidebarData }}</strong></p>

<button @click="updateProviderData">更新content组件数据</button>

</div>

</template>

<script>

export default {

inject: ['provider'],//从父组件提供的provide注入数据实例

data() {

return {

sidebarData: '',

};

},

computed: {

//需要同步的数据来源于provider的data属性

nowData: {

get: function() {

return this.provider.data;

},

set: function(val) {

this.provider.updateData(val);

},

},

},

mounted() {

this.sidebarData = this.nowData;

this.provider.addSubscriber(this);

},

methods: {

updateProviderData() {

this.nowData = '新的Content数据';

},

updateSelfData(val) {

this.sidebarData = val;

},

},

};

</script>

// provideData.js

import Subscription from './Subscription';

export default {

data() {

return {

data: '最初的数据',

};

},

provide() {

return {

provider: {

data: this.data,

subscribers: [],

addSubscriber(sub) {

this.subscribers.push(new Subscription(sub, this));

},

removeSubscriber(sub) {

this.subscribers.splice(this.subscribers.indexOf(sub), 1);

},

notifySubs() {

this.subscribers.forEach(sub => {

sub.update();

});

},

updateData(val) {

this.data = val;

this.notifySubs();

},

},

};

},

};

二、Vuex实现组件间通讯

Vuex是一个专为Vue.js应用开发的状态管理模式,它可以方便的在组件间传递状态。

1. Vuex基本使用

Vuex基本实现组件通讯,需要借助state、mutation、action、getter四个部分的配合实现。其中state是一个数据集中管理地方,mutation用于修改state的值,action是通知mutation调用的地方,而getter就是一个获取state数据某个属性的计算属性。

//store.js

import Vue from 'vue';

import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({

state: {

num: 0,

},

mutations: {

add(state, n = 1) {

state.num += n;

},

minus(state, n = 1) {

state.num -= n;

},

},

actions: {

addData({ commit }, n) {

//异步任务

setTimeout(() => {

commit('add', n);

}, 1000);

},

},

getters: {

doubleNum(state) {

return state.num * 2;

},

},

});

export default store;

2. Vue组件内使用Vuex

Vuex状态可以在组件中使用,在组件中可以调用mapState、mapMutation、mapAction、mapGetter等方法来获取state中数据、调用mutation等方法。

//调用num值

<template>

<div>

<p>num值:{{ num }}</p>

<p>doubleNum值:{{ doubleNum }}</p>

</div>

</template>

<script>

import { mapState, mapGetters } from 'vuex';

export default {

computed: {

...mapState({

num: state => state.num,

}),

...mapGetters({

doubleNum: 'doubleNum',

}),

},

};

</script>

3. Vue组件间使用Vuex通讯

在Vuex中,数据源和状态都集中在store中,因此,可以通过store作为组件间的数据媒介来实现数据的传递和通讯。

//组件A

<template>

<div>

<p>num值:{{ num }}</p>

<button @click="$store.commit('add')">加1</button>

</div>

</template>

<script>

export default {

computed: {

num() {

return this.$store.state.num;

},

},

};

</script>

//组件B

<template>

<div>

<p>num值:{{ num }}</p>

<button @click="$store.commit('minus')">减1</button>

</div>

</template>

<script>

export default {

computed: {

num() {

return this.$store.state.num;

},

},

};

</script>

三、总结

Vue组件通讯可以通过父组件向子组件传递数据,子组件向父组件发射事件传递数据来实现。如果是兄弟组件之间的数据传递,可以通过通过共同的父组件作为桥梁,父组件通过provide/inject方式提供一个数据实例,兄弟组件可以通过在inject中获取这个实例,并监听它的变化。当应用程序复杂时,可以使用Vuex来进行管理,通过store作为组件间的数据媒介来实现数据的传递和通讯。