一、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作为组件间的数据媒介来实现数据的传递和通讯。