1. 前言
在Vue开发中,组件是数据的展现和交互的封装。组件之间的通讯是Vue框架中最常见的问题之一,本文将会介绍如何在Vue中实现兄弟组件之间的通讯。
2. 父组件向子组件传递数据
2.1 props
Vue使用props属性来从父组件向子组件传递数据。子组件通过props属性定义接收的属性并通过this来访问传递过来的值。
//父组件
<template>
<div>
<child :message="parentMsg"></child>
</div>
</template>
<script>
import Child from './Child';
export default {
name: 'parent',
data() {
return {
parentMsg: '这是来自父组件的消息'
}
},
components: {
Child
}
}
</script>
//子组件
<template>
<div>
{{ message }}
</div>
</template>
<script>
export default {
name: 'child',
props: ['message']
}
</script>
props使用方式:
在父组件中用冒号(:)绑定数据到子组件的props中。
在子组件中使用props选项并指定接收的属性名称。
2.2 动态props
props属性支持使用js表达式,可以将props属性和父组件的数据动态绑定。Vue对props的改变不会影响父组件的状态,但是就算是引用类型也不会影响引用数据本身,在子组件中对引用类型的数据的修改也不会被父组件观察到。
//父组件
<template>
<div>
<child :message="parentMsg" :count="parentCount"></child>
</div>
</template>
<script>
import Child from './Child';
export default {
name: 'parent',
data() {
return {
parentMsg: '这是来自父组件的消息',
parentCount: 1
}
},
components: {
Child
}
}
</script>
//子组件
<template>
<div>
{{ message }} {{ count }}
</div>
</template>
<script>
export default {
name: 'child',
props: ['message', 'count']
}
</script>
3. 子组件向父组件传递数据
3.1 $emit
$emit触发一个父元素事件,并传递任意数据,父元素可以通过$on监听子元素事件并接收数据。
//父组件
<template>
<div>
<child @son-click="listenClick"></child>
</div>
</template>
<script>
import Child from './Child.vue';
export default {
name: 'parent',
methods: {
listenClick(res) {
console.log(res);
}
},
components: {
Child
}
}
</script>
//子组件
<template>
<div>
<button @click="handleClick">点击我</button>
</div>
</template>
<script>
export default {
name: 'child',
methods: {
handleClick() {
this.$emit('son-click', '这是来自子组件的数据');
}
}
}
</script>
$emit使用方式:
在子组件中使用this.$emit触发事件并传递数据
在父组件中使用@监听子组件事件并接收数据
4. 兄弟组件之间的通讯
4.1 $parent
可以使用$parent来在子组件中访问父组件的数据和方法,此方法不够优雅,父子级关系发生变化时会导致错误。
//组件A
<template>
<div>
<button @click="$parent.$emit('change', '我変な数据')">我变!</button>
</div>
</template>
//组件B
<template>
<div>
{{ msg }}
</div>
</template>
<script>
export default {
name: 'componentB',
data() {
return {
msg: ''
};
},
mounted() {
const that = this;
this.$parent.$on('change', function(res){
that.msg = res;
});
}
}
</script>
$parent缺点:
不能解决子组件之间通讯的问题
如果你的组件嵌套比较多,又多处需要调用$pantom值,那么显得比较混乱
如果组件结构调整就会导致产生异常
4.2 $refs
可以使用refs来获取子组件的引用,并直接访问子组件的 props 和 data 属性。
//组件A
<template>
<div>
<button @click="$refs.B.changeData('我变の数据')">我变!</button>
</div>
</template>
//组件B
<template>
<div>
{{ msg }}
</div>
</template>
<script>
export default {
name: 'componentB',
data() {
return {
msg: ''
};
},
methods: {
changeData(str) {
this.msg = str;
}
}
}
</script>
$refs优点:
适用于那些只在单个页面中复用的非常简单的组件,通常只是表单控件或一个按钮之类的。
浅组合的情况下谨慎使用,以防改变代码可能会很脆弱。
4.3 Event Bus
Event Bus 是一种Vue的高级技巧。这个技巧的基础是Vue实例可以作为中央事件总线:允许在任何组件上触发事件和监听事件。
//event-bus.js
import Vue from 'vue';
const bus = new Vue();
export default bus;
//组件A
<template>
<div>
<button @click="changeData('我变! 的数据')">我变!</button>
</div>
</template>
<script>
import bus from '../event-bus';
export default {
name: 'componentA',
methods: {
changeData(str) {
bus.$emit('change', str);
}
}
}
</script>
//组件B
<template>
<div>
{{ msg }}
</div>
</template>
<script>
import bus from '../event-bus';
export default {
name: 'componentB',
data() {
return {
msg: ''
};
},
created() {
const that = this;
bus.$on('change',function(res){
that.msg = res;
});
}
}
</script>
Event Bus优点:
非常适合大型的复杂应用程序,它需要进行跨多个组件通信(例如公共App组件等)。
最佳实践是在单独的event-bus.ts或event-bus.js小模块中导出Event Bus。
4.4 Vuex
在组件树中共享状态非常复杂并且极难维护,这是Vuex背后的基础思想,也是Vuex所解决的核心问题。
//store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
msg: '初始的数据'
},
mutations: {
change(state, value) {
state.msg = value;
}
},
actions: {
}
});
export default store;
//组件A
<template>
<div>
<button @click="changeData('我变の数据')">我变!</button>
</div>
</template>
<script>
import { mapMutations } from 'vuex';
export default {
name: 'componentA',
methods: {
...mapMutations(['change']),
changeData(str) {
this.change(str);
}
}
}
</script>
//组件B
<template>
<div>
{{ msg }}
</div>
</template>
<script>
import { mapState } from 'vuex';
export default {
name: 'componentB',
computed: {
...mapState(['msg'])
}
}
</script>
Vuex优点:
Vuex广泛应用于大型的复杂应用程序中。我们可以在其中使用属性、getters、mutators、操作和订阅状态等技术。
Vuex-store很少变化(不能使用this),当发生变化时,容易跟踪。但是组件会发生变化,由于一些bug,很难明确跟踪它们所绑定的值何时变化。此外,代码相对稳定的store意味着测试更加容易。
5. 总结
组件是Vue中数据展现和交互的封装,组件之间的通讯使用props、$emit、$parent、$refs、Event Bus和Vuex。在选择通讯方式时,需要据其优缺点和应用场景进行选择。