35-Vue脚手架-全局事件总线(使用全局事件总线优化Todo-List案例)

发布时间 2023-11-02 17:52:51作者: 马铃薯1

全局事件总线(GlobalEventBus)

1. 一种组件间通信的方式,适用于任意组件间通信

2. 安装全局事件总线

new Vue({
    ...
    // 生命周期 beforeCreate 这时vue还未解析模板,初始化的数据监测、数据代理还未开始
    beforeCreate() {
        // 安装全局事件总线
        Vue.prototype.$bus = this
    },
    ...
})

3. 使用事件总线

1)接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身

methods() {
    demo(data){...}
}

...

// 生命周期 mounted , 这时呈现的是经过 Vue编译的 DOM
mounted() {
    console.log("School",this)
    // 接收数据,在组件中给$bus绑定自定义事件
    this.$bus.$on("hello", this.demo}
}

2)提供数据:B组件想提供数据,也就是要触发在A组件绑定的事件

this.$bus.$emit("hello" , 数据)

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

beforeDestroy() {
      // 解绑自定义事件 hello
      this.$bus.$off("hello")
}

 

案例:使用全局事件总线,把Student组件的学生姓名属性,传递给School组件,并进行替换

src/components/School.vue(接收数据,以及解绑当前组件所用到的事件)

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

<script>
  export default{
    // eslint-disable-next-line vue/multi-word-component-names
    name:"School",
    data(){
      return{
        name:"马铃薯的博客园",
        address:"河北省邯郸市"
      }
    },
    // 生命周期 mounted , 这时呈现的是经过 Vue编译的 DOM
    mounted() {
      console.log("School",this)
      // 监听当前实例上自定义事件hello
      // this.x.$on("hello",(data)=>{
      //   console.log("我是School组件,收到了数据:",data)
      // })
      this.$bus.$on("hello",(data)=>{
        console.log("我是School组件,收到了数据:",data)
        this.name = data
      })
    },
    beforeDestroy() {
      // 解绑自定义事件 hello
      this.$bus.$off("hello")
    }
  }
</script>

<style scoped>
  .school{
    background-color: skyblue;
    padding: 5px;
  }
</style>

src/components/Student.vue(提供数据)

<template>
  <div class="student">
    <h2>学生姓名:{{name}}</h2>
    <h2>学生性别:{{sex}}</h2>
    <button @click="sendStudentName">把学生姓名给School组件</button>
  </div>
</template>

<script>
  export default{
    // eslint-disable-next-line vue/multi-word-component-names
    name:"School",
    data(){
      return{
        name:"马铃薯",
        sex:"",
      }
    },
    mounted() {
      console.log("Student",this)
    },
    methods:{
      sendStudentName() {
        // 触发当前实例上的自定义事件 hello
        // this.x.$emit("hello" ,666)
        this.$bus.$emit("hello" ,this.name)
      }
    }
  }
</script>

<style scoped>
  .student{
    background-color: pink;
    padding: 5px;
    margin-top: 30px;
  }
</style>

src/App.vue(无变动)

<template>
  <div class="app">
    <h1>{{msg}}</h1>

    <School></School>
    <Student></Student>

  </div>
</template>

<script>
  import Student from "@/components/Student.vue";
  import School from "@/components/School.vue"

  export default{
    name:"App",
    data(){
      return{
        msg:"你好啊"
      }
    },
    components:{
      Student:Student,
      School:School
    },
  }
</script>

<style>
 .app{
   background-color: gray;
   padding: 5px;
 }
</style>

src/main.js(安装全局事件总线)

import Vue from "vue"
import App from "./App.vue"

// 阻止 vue 在启动时生成生产提示
Vue.config.productionTip = false

// // 创建VueComponent实例对象
// const Demo = Vue.extend({})
// const d = new Demo()
//
//
// // Vue原型对象
// console.log(Vue.prototype)
//
// // vm和vc是存在一个重要的内置关系的: VueComponent.prototype.__proto__ === Vue.prototype
// // 让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。
// Vue.prototype.x = d


new Vue({
    el:"#app",
    render:h => h(App),
    // 生命周期 beforeCreate 这时vue还未解析模板,初始化的数据监测、数据代理还未开始
    beforeCreate() {
        // 安装全局事件总线,这里的this指的是vm,不用vc实例对象了
        // Vue.prototype.x = this

        // $bus 更专业
        Vue.prototype.$bus = this
    }
})