前言
前段时间,同事发现一个弹窗组件被多个页面复用,然后点击按钮出现了多次响应。明明页面都会被销毁掉的呀,为啥还会出现重复调用呢。
其实以前我也碰到过一两次,不知道啥情况后来没有再复现,再加上工期紧,当时就没有引起重视。这次同事碰到了,多次试验复现了。才深知当时挖的大坑啊没有填。
所以这次就单独弄了个demo专门复现并解决这个问题。也希望吸取教训,以后碰到问题都要记录下来,尽早早早早早解决啊,不然都是坑。
另外,文章里的关于父子组件的全局事件监听是错误的选择,请大家不要使用这种。(但是兄弟组件可以用文中这种全局监听的方式)
请用官方例子(遇到问题,请多用官方,不然直接参考其他同学的思路很可能挖坑。这里是以前直接搜索到eventbus的实现方式,请引以为戒,哈哈,我就做个反面教材吧
传送门在此
重复响应代码示例
首先我写了一个dialogx的小组件,里面只有一个点击按钮。当点击的时候,会触发一个btnClick
的事件。
然后我又写了两个页面用来测试重复响应。下面是 test1.vue
,至于test2
也一样,就不重新放图了。
然后,咱们来点点点点点点!就能发现,在test2
页面发起的事件,而test1
也响应了,这属于重复响应是不符合我们的项目需要的。
这...是咋回事~~??
经过查询相关资料,确定了问题在于没有过去的销毁事件响应。
好,我们出发去加上销毁逻辑。
加入销毁操作
于是我在dialogx.vue
中加入以下代码,在路由切换组件被销毁的时候,对btnClick
事件进行销毁。顺便打印一下 this.$root
看看里面是个啥结构。
然后就有了以下的操作,居然...居然 test2.vue 没法响应了。WTF,这又是啥情况。
冷静下来,好好分析。首先这种情况是因为我们加了销毁操作导致的,所以肯定是销毁的问题。
那么我们继续追踪。发现路由切换的各种操作的顺序是这样的。
这说明 什么问题?
新页面的
created
先执行,然后开始逐渐销毁老页面。仔细看看,我们能发现问题,test2.vue
在创建监听事件的时候,是在dialogx.vue
销毁之前的。人家刚创建好监听事件,由于执行顺序问题,被子组件给清除了,所以test2.vue
在点击发射时,是拦截不到的。
好,既然因为执行顺序的问题,那我们把监听事件注册放在 mounted
里。
果然,成功了。
再探索一下
对于事件的触发和监听,因为我们这是用 eventbus
实现的。为了看看里面具体是为什么,于是我打印了 this.$root
看看更细节的是为什么。
首先,每一次监听 this.$root.$on('btnClick')
都是一次事件注册,然后我在打印的结果里,找到了以下内容。
btnClick
是一个数组,这就意味着每一次btnClick
事件注册,都是往里存一个处理方法。
然后为了验证我的想法,我把 test2.vue
中的监听事件去了,直接看我们的 $off
效果。
是 null
,这就解释了为什么,刚才监听事件写在 created
里,为什么不生效了,因为整个事件都被设置为 null
了。
总结
为了达到组件复用不产生重复响应的问题。我们可以如下做。
1.在子组件里的
destroyed
方法里,对事件进行销毁操作($off)
2.在页面中mounted
方法中进行事件监听。
GitHub代码地址:https://github.com/XuXiaoGH/v...
写在最后
这次是一次异常排查过程的记录,如果对你有些许帮助,不妨收藏点个赞,这将是我继续的很大动力。
ps: GIF截图软件是 LICEcap ,非常好用,推荐一下。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。