Vue中事件总线eventBus的使用-发布订阅者模式,用于定义全局事件,实现非父子组件相互调用方法或传值——$on-监听事件订阅函数、$emit-发布事件发布函数、$off-销毁事件取消订阅

Vue中事件总线eventBus的使用-发布订阅者模式,用于定义全局事件,实现非父子组件相互调用方法或传值—— o n − 监 听 事 件 / 订 阅 函 数 、 on-监听事件/订阅函数、 on/emit-发布事件/发布函数、$off-销毁事件/取消订阅

1、eventBus事件总线的原理

eventBus是消息传递的一种方式,基于一个消息中心,订阅和发布消息的模式,称为发布订阅者模式

  • on(‘name’, fn)订阅消息——name:订阅的消息名称, fn: 订阅消息的函数(参数是接收的消息)

  • emit(‘name’, args)发布消息——name:发布的消息名称 , args:发布的消息。

发布订阅模式主要包含哪些内容呢?

  1. 发布函数,发布的时候执行相应的回调
  2. 订阅函数,添加订阅者,传入发布时要执行的函数,可能会携额外参数
  3. 一个缓存订阅者以及订阅者的回调函数的列表
  4. 取消订阅(需要分情况讨论)

为什么会使用发布订阅模式呢? 它的优点在于:

  • 实现时间上的解耦(组件,模块之间的异步通讯)
  • 对象之间的解耦,交由发布订阅的对象管理对象之间的耦合关系。

在之前我们只用过父传子,子传父进行传数据,这时候当组件嵌套比较深或比较复杂的情况(非父子关系),这时候就用到了事件总线 (EventBus)

如何理解事件总线呢,你可以理解为用来传输数据的一条线

在这里插入图片描述

注意点:有组件发布事件后 剩余的所有组件都可以进行监听事件

2、使用EventBus
2.1、创建事件总线

src/main.js

import Vue from 'vue'
// 创建事件总线   就相当于创建了一个新的vue实例
const bus = new Vue()
// 把bus挂载到了Vue的原型上, 保证所有的组件都能通过 this.$bus访问到事件总线
Vue.prototype.$bus = bus
2.2、页面使用 发布事件 - 传递值
// this.$bus.$emit('事件名', 额外参数)
this.$bus.$emit('send', 'hello')

//   this.$bus.$emit("nameOfEvent", {
//     name: "shy-destroyed"
//   });
3.3、订阅事件 - 接收组件值
// 1. 在created中订阅
// 2. 回调函数需要写成箭头函数
// this.$bus.$on('事件名', 事件回调函数)
this.$bus.$on('send', msg => {
  console.log(msg)  // 'hello'
})

 // this.$bus.$on("nameOfEvent", $event => {
 //      console.log($event);
 //  });
3、注意点

o n 先 执 行 , 再 执 行 on先执行,再执行 onemit触发事件 (嵌套关系)
因为是父子级组件嵌套关系的钩子函数执行顺序导致的。

父子嵌套生命周期——会先执行父组件中的前三个后,执行子组件的前三个,再去执行父组件的mounted。

在这里插入图片描述

3.1、验证为什么先执行 o n 在 执 行 on 在执行 onemit

父组件中

<template>
  <div>
  <son></son>
  </div>
</template>
<script>
import son from './Son.vue'
export default {
  components: {
    son
  },
  created() {
    console.log('父组件:我被创建啦')
    this.$bus.$emit('bus', 10)
  }
}
</script>

子组件

<template>
    <div>
  {{message}}
    </div>
</template>
 
<script>
export default {
  data () {
    return {
      message: ''
    }
  },
  created () {
    console.log('子组件:我被创建啦')
     this.$bus.$on('bus', (val) => {
       console.log(val)
      this.message = val
     })
  },
}
</script>

执行顺序显示

在这里插入图片描述

这时候是看不见任何接收信息的,原因就是——没有等子组件 o n 去 注 册 事 件 后 就 执 行 了 父 组 件 on去注册事件后就执行了父组件 onemit ,所以接收不到信息。

解决方法:

把父组件中的 e m i t 事 件 放 在 m o u n t e d 钩 子 函 数 中 等 待 子 组 件 创 建 并 注 册 emit事件放在mounted钩子函数中 等待子组件创建并注册 emitmountedon事件后再去触发$emit。 只适合嵌套关系 可能出现兄弟关系 也要看情况进行使用。

4、移除事件监听

示例

父组件中没两秒进行一次传递 点击v-if后将子组件进行 销毁或重新创建

父组件

<template>
  <button @click="isShow=!isShow"> {{isShow?'销毁':'重建'}}  </button>
  <son v-if="isShow=isShow">son</son>
  </div>
</template>
<script>
import son from './Son.vue'
export default {
  components: {
    son
  },
  data () {
    return {
      isShow: true
    }
  },
   created () {
   console.log('父组件:我被创建啦')
   setInterval(() => {
   this.$bus.$emit('bus', 10)
    }, 2000)
   }
}

子组件

<template>
    <div>
  {{message}}
    </div>
</template>
 
<script>
export default {
  data () {
    return {
      message: null
    }
  },
  created () {
    console.log('子组件:我被创建啦')
    this.$bus.$on('bus', (val) => {
      console.log(val)
      this.message = val
    })
  }
}
</script>

问题点:

当点击销毁子组件的时候 子组件还能接收到数据吗?对应的回调函数还能在执行吗?

答案是 会,事件订阅功能是$eventBus对象完成的,与组件无关,当你点击销毁后,再点击创建又会多了一个订阅事件,依次类推每次点击新建后都会多一个订阅事件。

在这里插入图片描述

造成原因:事件订阅是通过$eventBus对象完成的 与组件无关

如果不移除事件监听 并且会造成内存泄漏

在son组件中修改

  created () {
    console.log('子组件:我被创建啦')
    const m = 1 * 1024 * 1024
    const arr = new Array(m).fill('a')
 
    this.$bus.$on('bus', function f1 (val) {
      // 注意这里有一个闭包
      console.log(val, 'son listen... bus', arr[1])
    })
  },

在这里插入图片描述

通过v-if 销毁和重新创建来看通过数据发现 销毁后并没有对空间进行释放

解决方案: 在子组件销毁后进行取消订阅事件

  destroyed () {
    // 取消对bus事件的监听
    this.$bus.$off('bus')
  }

对bus取消事件监听后 内存得到了释放

在这里插入图片描述

5、总结:

1、任何组件都可以在事件总线中发布事件 this.$bus.$emit('xxx','传递参数')

2、任何组件都可以在事件总线中监听事件 this.$bus.$on('xxx',(接收参数)=>{ 对形参进行操作 })

3、main.js注册空的Vue对象, 只负责$on注册事件, e m i t 触 发 事 件 , 一 定 要 确 保 emit触发事件, 一定要确保 emit,on先执行

4、Vue.$off 移除自定义事件监听器。

  • $off() 会取消所有的事件订阅;如果没有提供参数,则移除所有的事件监听器;

  • $off(‘事件名’) 会取消指定事件名的;如果只提供了事件,则移除该事件所有的监听器;

  • $off(‘事件名’, 回调) 会取消指定事件名的,指定回调。如果同时提供了事件与回调,则只移除这个回调的监听器。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值