一次Vue2 bug排查过程

今天在改一个简单业务需求的时候遇到一个bug,排查了一个小时,最后发现与vue的diff有关,简单记录一下过程。

环境

是一个比较老的项目,使用Vue2+TS+class component。依赖版本为

  • vue 2.6.11
  • typescript 3.2.4
  • vuelidate 0.7.5
  • webpack 4.29.5
  • vue-class-component 7.2.2
  • bootstrap 4.5.3
  • bootstrap-vue 2.21.2

问题描述

sfc

是一个详情页面,created中获取后端返回数据并展示,页面本身没有特别复杂的逻辑。DOM结构类似上图所示,第一组radio切换会影响v-if中内容的展示。第二组、第三组是两组不相关的radio。

出现的问题是,进入页面后,第三组radio是没有勾选的,也就是两个选项都没有被勾选,但后端返回的数据是正常的,第一组与第二组的勾选也是正常的。

上图只是简化后的结构,不是复现,这个问题没法复现,原项目DOM结构比这个复杂,但与问题相关的关键DOM结构就这些。

解决方法

先说解决方法,在

上添加key(图中是解决后的,已经加了key),或者改成

排查过程

先检查vue dev tools,看看v-model绑定的变量是否有值,发现确实有值。然后去看子组件props,发现值也是对的。由于原先项目里第二组、第三组radio是有联动的(@input="someEvent"),以为是什么触发了input事件导致的问题,去掉了input,结果还是有问题,依旧不勾选,这个时候就有点怀疑是bootstrap-vue的问题了。

这个时候我先尝试了注释掉第二组、第三组radio,发现其他所有组件都是正常的;只注释第三组radio,结果第二组radio也不显示勾选了;只注释第二组radio,第三组radio此时还是不勾选的。

这个时候我还是怀疑bootstrap-vue的问题,然后去组件源码里找。定义radio是否checked的部分在mixins/form-radio-check.js里:

const $input = h('input', {  
        // 省略
      domProps: {
        value: this.value,
        checked: this.isChecked
      },
      // 省略
})

随后我在下文打条件断点,当input的name为name3时观察this.isChecked值。然后也行不通,每个相同的name对应两个radio的选项,在这个$input上我也看不出到底是哪个radio的值…

到这里似乎陷入了死局。这个时候我想,这个地方之前是不是正常的来着?(我改的这部分业务就是上图中v-if切换相关的部分)。之后把v-if这部分注释掉,发现就正常了。这时候心里大概有个数了,只需要验证一下。把v-if换成v-show,或者加个key发现都没有问题了。看来确实是和vue2的diff算法有关,v-if的这个div应该是被错误地复用了。没有再深入往下打断点查是哪块判断导致的dom复用了,估计也不太好查。以后如果遇上这种奇怪的问题可以优先考虑下是不是diff相关的问题。

你可能感兴趣的:(一次Vue2 bug排查过程)