在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递。
父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息。看看它们是怎么工作的。

父组件通过 prop 给子组件下发数据:
1
2
3
4
5
| Vue.component('child', {
// 在 JavaScript 中使用 camelCase
props: ['myMessage'],
template: '<span>{{ myMessage }}</span>'
})
|
1
2
| <!-- 在 HTML 中使用 kebab-case -->
<child my-message="hello!"></child>
|
子组件通过事件给父组件发送消息:
1
2
3
4
5
| <div id="message-event-example" class="demo">
<p v-for="msg in messages">{{ msg }}</p>
<button-message v-on:message="handleMessage"></button-message>
<!-- 使用 $on(eventName) 监听事件 -->
</div>
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| Vue.component('button-message', {
template: `<div>
<input type="text" v-model="message" />
<button v-on:click="handleSendMessage">Send</button>
</div>`,
data: function () {
return {
message: 'test message'
}
},
methods: {
handleSendMessage: function () {
this.$emit('message', { message: this.message }) // 使用 $emit(eventName, optionalPayload) 触发事件
}
}
})
new Vue({
el: '#message-event-example',
data: {
messages: []
},
methods: {
handleMessage: function (payload) {
this.messages.push(payload.message)
}
}
})
|
非父子组件通信
有时候两个组件也需要通信(非父子关系)。在简单的场景下可是使用一个空的vue实例作为中央事件总线:
1
2
3
4
5
6
7
| //触发组件 A 中的事件
bus.$emit('is-selected', 1)
``````js
//在组件 B 创建的钩子中监听事件
bus.$on('is-selected', function(id){
})
|
这个集中式的事件中间件就是 Bus。可以将bus定义到全局:
app.js
1
2
3
4
5
6
| var eventBus = {
install(Vue,options) {
Vue.prototype.$bus = vue
}
};
Vue.use(eventBus);
|
然后在组件中,可以使用$emit, $on, $off 分别来分发、监听、取消监听事件:
分发事件的组件
1
2
3
4
5
6
7
| // ...
methods: {
todo: function () {
this.$bus.$emit('todoSth', params); //params是传递的参数
//...
}
}
|
监听的组件
1
2
3
4
5
6
7
8
9
10
11
12
| // ...
created() {
this.$bus.$on('todoSth', (params) => { //获取传递的参数并进行操作
//todo something
})
},
// 最好在组件销毁前
// 清除事件监听
beforeDestroy () {
this.$bus.$off('todoSth');
},
|
如果需要监听多个组件,只需要更改 bus 的 eventName:
1
2
3
4
5
6
7
8
9
10
| // ...
created() {
this.$bus.$on('firstTodo', this.firstTodo);
this.$bus.$on('secondTodo', this.secondTodo);
},
// 清除事件监听
beforeDestroy () {
this.$bus.$off('firstTodo', this.firstTodo);
this.$bus.$off('secondTodo', this.secondTodo);
},
|