Vue 采用基于组件的开发方式,那么组件之间的通信必不可少:比如父组件要给子组件传递数据,子组件将它内部发生的事情告知给父组件,因此定义一个良好的接口尽可能将组件解耦显得尤为重要,这保证不同的组件可以在相对独立的环境中开发测试,而且更方便阅读理解以及组件复用。
Vue 父子组件之间通信主要采取两种方式,通常可以总结为 props down、events up,父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息,这点跟 React 一模一样。
Vue2.0 废除了 events、dispatch、broadcast 几个事件,官方推荐使用 全局事件驱动 或者 vuex代替,目前只剩下 vm.on、vm.once、vm.off、vm.emit 几个事件。
Vue 组件之间的作用域是相互隔离的,父组件向子组件传值只能通过 props 的方式,子组件不能直接调用父组件的数据。在子组件中,如果需要调用父组件传来的参数,必须显式的声明 props。
Vue.component('child', {
props: ['message'],
template: '<span>{{ message }}</span>'
})父组件向子组件传值
<child message="hello!"></child>props 传递值只能父组件向子组件传递,不能反回来,每当父组件更新时,子组件中的 props 会自动更新。如果在子组件中更改 props,Vue 控制台会给出 warning。因此如果需要在子组件中更改 props 通常会把其作为初始值赋值给某个变量,然后变量的值,或者在计算属性中定义一个基于 props 的值。
如果子组件需要把信息传达给父组件,可以使用 v-on 绑定自定义事件
<div id="counter-event-example">
<p>{{ total }}</p>
<button-counter v-on:increment="incrementTotal"></button-counter>
<button-counter v-on:increment="incrementTotal"></button-counter>
</div>我们给 button-counter 绑定了一个自定义事件 increment,v-on 绑定事件还可以简写为 @increment=""。
Vue.component('button-counter', {
template: '<button v-on:click="increment">{{ counter }}</button>',
data: function () {
return {
counter: 0
}
},
methods: {
increment() {
this.counter += 1
this.$emit('increment')
}
},
})
new Vue({
el: '#counter-event-example',
data: {
total: 0
},
methods: {
incrementTotal() {
this.total += 1
}
}
})button-counter 组件的模板中包含一个 button,其 click 事件会触发($emit)自定义事件 increment,因此每次在子组件中点击一次 button,父组件中都会调用 incrementTotal() 方法。
上面讲的两种方法都父子组件之间的通信,有时候非父子关系的组件也需要通信。在 Vue1.0 时代,可以通过 dispatch 和 broadcast 来解决,首先 dispatch 到根组件,然后再 broadcast 到子组件。Vue2.0 中官方推荐用 event bus 或者 vuex 解决,event bus 的本质是一个发布者订阅者模式。
var bus = new Vue()bus.$emit('id-selected', 1)bus.$on('id-selected', function (id) {})下面是 stackoverflow 上面的一个例子
<div id="example">
<Display></Display>
<Increment></Increment>
</div>var bus = new Vue()
Vue.component('Increment', {
template: `<button @click="increment">+</button>`,
data: function() {
return {count: 1}
},
methods: {
increment: function(){
var increment = this.count++
bus.$emit('inc', increment)
}
}
})
Vue.component('Display', {
template: `<h3>Clicked: {{count}} times</h3>`,
data: function(){
return {count: 0}
},
created: function(){
bus.$on('inc', function(num){
this.count = num
}.bind(this))
}
})
new Vue({
el: "#example",
})Vuex 是 Vue 组件的一个状态管理器,相当于一个只为 Vue 服务的 Redux。下面一个图能很好的反映出 Vuex 是如何让组件之间通信的。

下面是 Vuex 官网上给出的一个 计数器的例子
<div id="app">
<p>{{ count }}</p>
<p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</p>
</div>const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment: state => state.count++,
decrement: state => state.count--
}
})
const app = new Vue({
el: '#app',
computed: {
count() {
return store.state.count
}
},
methods: {
increment() {
store.commit('increment')
},
decrement() {
store.commit('decrement')
}
}
})在 Vuex 中,store 是组件状态的一个容器,上面的 store 中定义了一个初始的 state 对象,和两个 mutations 函数。我们可以通过 store.state 来获取状态对象,以及通过 store.commit 方法触发状态变更。要注意的是,我们不能直接更改 store 中的状态,改变 store 中的状态的唯一途径就是显式地提交(commit) mutations。
如果想要在 vue2 中使用 dispatch 和 broadcast,可以参考 vue2 组件通信——使用 dispatch 和 broadcast