介绍

在 vue 里我们可以通过全局事件总线来实现任意组件之间通信

它的原理是给 Vue 的原型对象上面添加一个属性。这样的话我所有组件的都可以访问到这个属性,然后可以通过这个属性来访问其他组件给这个属性上面绑定的一些方法,从而去传递数据。而且这个属性还可以去访问 Vue 实例对象上的方法。因为 Vue 组件构造函数的原型对象的原型对象是指向 Vue 的原型对象的

使用

使用之前的 Student.vue 和 School.vue 的代码。现在我们实现 Student.vue 向 School.vue 中传递数据。先看代码:

main.js中,增加以下代码

//引入Vue
import Vue from 'vue';
//引入App
import App from './App';

//关闭vue的生产提示
Vue.config.productionTip = false

//创建vm
new Vue({
    el: "#app",
    render: h => h(App),
    beforeCreate() {
        Vue.prototype.$bus = this//安装全局事件总线
    }
})

School.vue 中给 $bus 绑定 hello 事件

<template>
  <div class="school">
    <h2>学校名称:{{ name }}</h2>
    <h2>学校地址:{{ address }}</h2>
  </div>
</template>

<script>
export default {
  name: "School",
  data() {
    return {
      name: "三里屯小学",
      address: "北京"
    }
  },
  mounted() {
    //给$bus绑定hello事件
    this.$bus.$on("hello", (data) => {
      console.log("我是school组件,到了数据:" + data);
    })
  },
  beforeDestroy() {
    this.$bus.off("hello")
  }
}
</script>

<style scoped>

</style>

Student.vue 中触发事件

<template>
  <div class="student">
    <h2>学生姓名:{{ name }}</h2>
    <h2>学生年龄:{{ age }}</h2>
    <button @click="sendStudentName">点我向School组件传递学生姓名</button>
  </div>
</template>

<script>
export default {
  name: "Student",
  data() {
    return {
      name: "张三",
      age: 18
    }
  },
  methods:{
    sendStudentName(){
      this.$bus.$emit("hello",this.name)
    }
  }
}
</script>

<style scoped>

</style>

在这里插入图片描述

总结

全局事件总线(GlobalEventBus)
1.一种组件问通信的方式,适用于任意组件问通信
2.安装全局事件总线:

new Vue({
    ......
    beforeCreate() {
        Vue.prototype.$bus = this//安装全局事件总线,$bus就相当于当前vm
    },
    ......
})

3.使用事件总线:
①.接收数据:A组件想接收数据,则在A组件中给 $bus 绑定自定义事件,事件的回调留在A组件自身

methods(){
	demo(data){......}
}
......
mounted() {
    //给$bus绑定hello事件
    this.$bus.$on("xxx",this.demo)
}

或者不写上边的 method,直接写成一个箭头函数

②.提供数据:this.$bus.$emit( " xxx",数据)

4.最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件

todolist 改为全局事件总线

当我们删除和勾选一个任务时,实际上操作的是 Item 组件。通过 Item 组件操作 App.vue 中的数据。我们之前的写法是,在App.vue中先把删除和勾选的方法传给 List 组件,然后 List 传给了 Item。实际上 List 并没有用这些方法,只是进行了传递。所以这里适合用全局事件总线

修改 main.js

//引入Vue
import Vue from 'vue';
//引入App
import App from './App';

//关闭vue的生产提示
Vue.config.productionTip = false

//创建vm
new Vue({
    el: "#app",
    render: h => h(App),
    beforeCreate() {
        Vue.prototype.$bus = this
    }
})

App.vue 中不给 List 传东西了,同时 绑定事件

<List :todos="todos"/>

<script>
......
export default {
	......
  mounted() {
    this.$bus.$on("checkTodo",this.checkTodo)
    this.$bus.$on("deleteTodo",this.deleteTodo)
  },
  destroyed() {
    this.$bus.$off("checkTodo")
    this.$bus.$off("deleteTodo")
  }
}
</script>
......

相应的 List 中也不用接收了,也不需要给 Item 传了

<template>
  <div>
    <ul class="todo-main">
      <Item v-for="todoObj in todos"
            :key="todoObj.id"
            :todo="todoObj"
      />
    </ul>
  </div>
</template>

<script>
import Item from "./Item"

export default {
  name: "List",
  props:["todos"],
  components: {
    Item
  }
}
</script>

Item 中也不需要接收了,触发方式也需要修改

export default {
  name: "Item",
  props:['todo'],
  methods:{
    //勾选 or 取消勾选
    handleCheck(id){
      //this.checkTodo(id)
      this.$bus.$emit("checkTodo",id)
    },
    //删除
    handleDelete(id){
      if(confirm("确认删除吗?")){
        //this.deleteTodo(id)
        this.$bus.$emit("deleteTodo",id)
      }
    }
  }
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐