vue 组件通信

3 minute read

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

父组件通过 prop 给子组件下发数据:

1Vue.component('child', {
2  // 在 JavaScript 中使用 camelCase
3  props: ['myMessage'],
4  template: '<span>{{ myMessage }}</span>'
5})
1<!-- 在 HTML 中使用 kebab-case -->
2<child my-message="hello!"></child>

子组件通过事件给父组件发送消息:

1<div id="message-event-example" class="demo">
2  <p v-for="msg in messages">{{ msg }}</p>
3  <button-message v-on:message="handleMessage"></button-message>
4  <!-- 使用 $on(eventName) 监听事件 -->
5</div>
 1Vue.component('button-message', {
 2  template: `<div>
 3    <input type="text" v-model="message" />
 4    <button v-on:click="handleSendMessage">Send</button>
 5  </div>`,
 6  data: function () {
 7    return {
 8      message: 'test message'
 9    }
10  },
11  methods: {
12    handleSendMessage: function () {
13      this.$emit('message', { message: this.message })   // 使用 $emit(eventName, optionalPayload) 触发事件 
14    }
15  }
16})
17
18new Vue({
19  el: '#message-event-example',
20  data: {
21    messages: []
22  },
23  methods: {
24    handleMessage: function (payload) {
25      this.messages.push(payload.message)
26    }
27  }
28})

非父子组件通信

有时候两个组件也需要通信(非父子关系)。在简单的场景下可是使用一个空的vue实例作为中央事件总线:

1let bus = new Vue()
1//触发组件 A 中的事件
2bus.$emit('is-selected', 1)
3``````js
4//在组件 B 创建的钩子中监听事件
5bus.$on('is-selected', function(id){
6
7})

这个集中式的事件中间件就是 Bus。可以将bus定义到全局: app.js

1var eventBus = {
2    install(Vue,options) {
3        Vue.prototype.$bus = vue
4    }
5};
6Vue.use(eventBus);

然后在组件中,可以使用$emit, $on, $off 分别来分发、监听、取消监听事件: 分发事件的组件

1// ...
2methods: {
3  todo: function () {
4    this.$bus.$emit('todoSth', params);  //params是传递的参数
5    //...
6  }
7}

监听的组件

 1// ...
 2created() {
 3  this.$bus.$on('todoSth', (params) => {  //获取传递的参数并进行操作
 4      //todo something
 5  })
 6},
 7
 8// 最好在组件销毁前
 9// 清除事件监听
10beforeDestroy () {
11  this.$bus.$off('todoSth');
12},

如果需要监听多个组件,只需要更改 bus 的 eventName:

 1// ...
 2created() {
 3  this.$bus.$on('firstTodo', this.firstTodo);
 4  this.$bus.$on('secondTodo', this.secondTodo);
 5},
 6// 清除事件监听
 7beforeDestroy () {
 8  this.$bus.$off('firstTodo', this.firstTodo);
 9  this.$bus.$off('secondTodo', this.secondTodo);
10},