10

前言

前段时间,同事发现一个弹窗组件被多个页面复用,然后点击按钮出现了多次响应。明明页面都会被销毁掉的呀,为啥还会出现重复调用呢。

其实以前我也碰到过一两次,不知道啥情况后来没有再复现,再加上工期紧,当时就没有引起重视。这次同事碰到了,多次试验复现了。才深知当时挖的大坑啊没有填。

所以这次就单独弄了个demo专门复现并解决这个问题。也希望吸取教训,以后碰到问题都要记录下来,尽早早早早早解决啊,不然都是坑。

另外,文章里的关于父子组件的全局事件监听是错误的选择,请大家不要使用这种。(但是兄弟组件可以用文中这种全局监听的方式)
请用官方例子(遇到问题,请多用官方,不然直接参考其他同学的思路很可能挖坑。这里是以前直接搜索到eventbus的实现方式,请引以为戒,哈哈,我就做个反面教材吧
传送门在此

重复响应代码示例

首先我写了一个dialogx的小组件,里面只有一个点击按钮。当点击的时候,会触发一个btnClick的事件。

clipboard.png

然后我又写了两个页面用来测试重复响应。下面是 test1.vue,至于test2也一样,就不重新放图了。

clipboard.png

然后,咱们来点点点点点点!就能发现,在test2页面发起的事件,而test1也响应了,这属于重复响应是不符合我们的项目需要的。

clipboard.png

这...是咋回事~~??

clipboard.png

经过查询相关资料,确定了问题在于没有过去的销毁事件响应

好,我们出发去加上销毁逻辑。

加入销毁操作

于是我在dialogx.vue中加入以下代码,在路由切换组件被销毁的时候,对btnClick事件进行销毁。顺便打印一下 this.$root看看里面是个啥结构。

clipboard.png

然后就有了以下的操作,居然...居然 test2.vue 没法响应了。WTF,这又是啥情况。

clipboard.png

clipboard.png

冷静下来,好好分析。首先这种情况是因为我们加了销毁操作导致的,所以肯定是销毁的问题。
那么我们继续追踪。发现路由切换的各种操作的顺序是这样的。

clipboard.png

这说明 什么问题?

新页面的created先执行,然后开始逐渐销毁老页面。仔细看看,我们能发现问题,test2.vue在创建监听事件的时候,是在dialogx.vue销毁之前的。人家刚创建好监听事件,由于执行顺序问题,被子组件给清除了,所以 test2.vue在点击发射时,是拦截不到的。

好,既然因为执行顺序的问题,那我们把监听事件注册放在 mounted里。

果然,成功了。

clipboard.png

再探索一下

对于事件的触发和监听,因为我们这是用 eventbus实现的。为了看看里面具体是为什么,于是我打印了 this.$root看看更细节的是为什么。

首先,每一次监听 this.$root.$on('btnClick')都是一次事件注册,然后我在打印的结果里,找到了以下内容。

clipboard.png

btnClick 是一个数组,这就意味着每一次btnClick事件注册,都是往里存一个处理方法。
然后为了验证我的想法,我把 test2.vue中的监听事件去了,直接看我们的 $off效果。

clipboard.png

null,这就解释了为什么,刚才监听事件写在 created里,为什么不生效了,因为整个事件都被设置为 null了。

总结

为了达到组件复用不产生重复响应的问题。我们可以如下做。

1.在子组件里的destroyed方法里,对事件进行销毁操作($off)
2.在页面中 mounted方法中进行事件监听。

GitHub代码地址:https://github.com/XuXiaoGH/v...

写在最后

这次是一次异常排查过程的记录,如果对你有些许帮助,不妨收藏点个赞,这将是我继续的很大动力。

ps: GIF截图软件是 LICEcap ,非常好用,推荐一下。


城南
5.5k 声望884 粉丝