vue中eventbus被多次触发(vue中使用eventbus踩过的坑)

2020-01-08 13:30:30

在做vue evenbus的时候,我们不面会遇到多测触发监听的问题,不但重新生成或者多次生成组件,以及开发热加载模式中都会发生

不过这些问题,跨组件调用方法的神奇,supervue已经为我们解决了这些问题。我们可以去用一下。

点击查看supervue用法

下面我们来解释下为什么会出现上面所说的问题。


问题参考地址 vue中eventbus被多次触发(vue中使用eventbus踩过的坑)


一开始的需求是这样子的,我为了实现两个页面组件之间的数据传递,假设我有页面A,点击页面A上的某一个按钮之后,页面会自动跳转到页面B,同时我希望将页面A上的某一些参数携带过去给页面B。


然后我就想,这不就是不同组件之间的数据传递问题而已吗?直接用bus 巴士事件来传递数据不就行了吗。于是,我就很愉快地进行了。关于vue中的eventbus的使用,我之前在一篇vue中的数据传递中有提到过。 



先给你们看一下我一开始的代码:


实现目标: 

点击之后,bus emit事件,然后顺便跳转路由到/moneyRecord页面。

接下来就是在MoneyRecord页面中去on接收这个事件,然后接受参数。

// 这是页面A的内部触发bus事件的代码

  editList (index, date, item) {

//  点击进入编辑的页面,需要传递的参数比较多。

      console.log(index, date, item)

      bus.$emit('get', {

        item: item.type,

        date: date

      })

      this.$router.replace({path: '/moneyRecord'})

    }

 

// moneyRecord页面

created () {

    //这里我将icon的list给保存下来了

    bus.$on('get', this.myhandle)

  },

methods: {

  myhandle (val) {

      console.log(val, '这是从上个页面传递过来的参数')

    }

}

就当我欣喜若狂的时候,觉得自己只要在页面A触发了get事件,页面B中就会理所当然的接受了数据。然而,结果却不如人意,看一下下面的动图。


主要是看“”这是从上个页面传来的数据这一行数据的输出次数情况来判断事件触发次数。“”



test.gif

不知道你有没有发现,就是我第一次进去list页面的时候,我随便点击一下list下的任何一个item,控制台没有输出。但是当我第二次再点击触发事件的时候,就会输出一个测试数据。再一次进去点击,就输出两个数据。。。依次增加了。(控制台上那个“这是从上个页面传来的数据”就是测试数据)


所以,有两个问题。


问题:


问题1: 为什么第一次触发的时候页面B中的on事件没有被触发

问题2: 为什么后面再一次依次去触发的时候会出现,每一次都会发现好像之前的on事件分发都没有被撤销一样,导致每一次的事件触发执行越来越多。

解决


针对问题1

这个还得从vue的生命周期说起了,我先进行了测试,就是当从页面组件A跳转到页面组件B的时候,两个组件的生命周期分别是怎么样的,关于vue的生命周期具体每一个时期做什么事情我就不再赘述了,下面po一张vue生命周期的图。



image.png

我自己做了实验来验证,这个页面跳转过程中,这两个组件的生命周期的执行情况。


// 我分别在页面A和页面B中去添加以下代码:

beforeCreate () {

   console.group('%c%s', 'color:red', 'beforeCreate 创建前状态===============组件2》')

 },

 created () {

   console.group('%c%s', 'color:red', 'created 创建完毕状态===============组件2》')

 },

 beforeMount () {

   console.group('%c%s', 'color:red', 'beforeMount 挂载前状态===============组件2》')

 },

 mounted () {

   console.group('%c%s', 'color:red', 'mounted 挂载状态===============组件2》')

 },

 beforeUpdate () {

   console.group('%c%s', 'color:red', 'beforeUpdate 更新前状态===============组件2》')

 },

 updated () {

   console.group('%c%s', 'color:red', 'updated 更新状态===============组件2》')

 },

 beforeDestroy () {

   console.group('%c%s', 'color:red', 'beforeDestroy 破前状态===============组件2》')

 },

 destroyed () {

   console.group('%c%s', 'color:red', 'destroyed 破坏状态===============组件2》')

 }

// 另外一个组件的我就不放出来了

测试结果图:



test.gif


image.png

其实,可以通过结果清楚看到,当我们还在页面A的时候,页面B还没生成,也就是页面B中的 created中所监听的来自于A中的事件还没有被触发。这个时候当你A中emit事件的时候,B其实是没有监听到的。


再看一下,红色的是B页面组件,当你从页面A到页面B跳转的时候,发生了什么?首先是先B组件先created然后beforeMount接着A组件才被销毁,A组件才执行beforeDestory,以及destoryed.


所以,我们可以把A页面组件中的emit事件写在beforeDestory中去。因为这个时候,B页面组件已经被created了,也就是我们写的$on事件已经触发了


所以可以,在beforeDestory的时候,$emit事件。


// 修改一下A页面中的代码:

// 这是原先的代码

  editList (index, date, item) {

//  点击进入编辑的页面,需要传递的参数比较多。

      console.log(index, date, item)

      this.item = item.type

      this.date = date

      this.$router.replace({path: '/moneyRecord'})

    }

// 重新在data属性内部定义新的变量,来存储要传过去的数据;

然后:

 beforeDestroy () {

 console.log(this.highlight, '这是今年的数据', this, '看看组件销毁之前会发生什么')

 bus.$emit('get', {

        item: this.item,

        date: this.date

      })

 },

接下来。看一下修改之后的效果



test.gif

可以看到,就是第一次点击list的时候,也就是第一次触发emit事件的时候,控制太就输出了,所以在beforeDestoryed去$emit是起到作用的,B页面组件也监听$on到了。


但是,好像,就是事件的触发还是会依次增加,就是控制台的输出每次都有所增加了。。。


解决:

看一下github上提出的。issue

https://github.com/vuejs/vue/issues/3399



image.png

尤大大提出了以下解决:



image.png

*就是说,这个$on事件是不会自动清楚销毁的,需要我们手动来销毁。(不过我不太清楚这里的external bus 是什么意思,有大神能解答一下的吗,尤大大也提到如果是注册的是external bus 的时候需要清除)****


所以。我在B组件页面中添加Bus.$off来关闭。代码如下:


// 在B组件页面中添加以下语句,在组件beforeDestory的时候销毁。

  beforeDestroy () {

    bus.$off('get', this.myhandle)

  },

来看一下输出的结果


  • 2020-12-16 22:04:03

    基于本地代理的边下边播技术分析

    我们熟知的边下边播技术,是迅雷提供的,还有之前的快播、快车等工具,它们使用的技术基本上都是P2P下载技术。 P2P下载技术,本质上它并不是C-S的架构,P2P----> Peer to Peer,实际上它将各个客户端的资源调度起来,给上传资源种子,方便后续的下载者可以快速有效的下载资源,这种方式需要服务器整合各个Client,在有用户需要下载的情况下,服务器能及时调度资源,开始给下载者提供资源信息,保证下载者下载资源越快越好。P2P的下载方式后面我们专门介绍一下。这儿不继续展开了。

  • 2020-12-16 22:07:44

    Android视频点播-边播边缓存

    一些知名的视频app客户端(优酷,爱奇艺)播放视频的时候都有一些缓存进度(二级进度缓存),qq,微信有关的小视频,还有一些短视频app,都有边播边缓的处理。还有就是当文件缓存完毕了再次播放的话就不再请求网络了直接播放本地文件了。既节省了流程又提高了加载速度。 今天我们就是来研究讨论实现这个边播边缓存的框架,因为它不和任何的业务逻辑耦合。

  • 2020-12-16 22:46:44

    基于coturn项目的stun/turn服务器搭建

    webrtc是google推出的基于浏览器的实时语音-视频通讯架构。其典型的应用场景为:浏览器之间端到端(p2p)实时视频对话,但由于网络环境的复杂性(比如:路由器/交换机/防火墙等),浏览器与浏览器很多时候无法建立p2p连接,只能通过公网上的中继服务器(也就是所谓的turn服务器)中转。示例图如下:

  • 2020-12-16 23:06:05

    Rocket.Chat推送信息

    Rocket.Chat推送消息 Rocket.Chat是一个开源实时通讯平台, 支持Windows, Mac OS, Linux. 支持聊天, 文件上传, 视频通话, 语音通话功能. 向Rocket.Chat推送消息 以下示例可以转为别的语言的版本, 本示例使用Linux平台的curl测试, curl非常强大. 登陆 首先需要登陆Rocket.Chat服务器

  • 2020-12-17 09:01:23

    对BitTorrent Tracker源码分析

    tracker服务器是BT下载中必须的角色。一个BT client 在下载开始以及下载进行的过程中,要不停的与 tracker 服务器进行通信,以报告自己的信息,并获取其它下载client的信息。这种通信是通过 HTTP 协议进行的,又被称为 tracker HTTP 协议,它的过程是这样的: client 向 tracker 发一个HTTP 的GET请求,并把它自己的信息放在GET的参数中;这个请求的大致意思是:我是xxx(一个唯一的id),我想下载yyy文件,我的ip是aaa,我用的端口是bbb。。。

  • 2020-12-17 10:55:48

    html5 video p2p research

    节约带宽,减少缓冲时间,提升服务质量,处理峰值流量, 视频观看的人越多,播放越流畅。

  • 2020-12-17 10:57:34

    使用 MediaSource 搭建流式播放器

    Media Source Extensions(媒体源扩展)大大地扩展了浏览器的媒体播放功能,提供允许JavaScript 生成媒体流。这可以用于自适应流(adaptive streaming,也是我毕设的研究方向)及随时间变化的视频直播流(live streaming)等应用场景。