一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第13天,点击查看活动详情。
前言
今天在调试vue代码的时候发现一个问题,watch监听某个值变化的时候第一次监听不到。业务场景是有一个模块(子组件)需要根据父组件的中的某个值来控制显示和隐藏,并且这个值在子组件中还被watch监听,当这个值变化的时候要调用相应的接口
原始代码(也就是有问题的代码)
代码如下
父组件:
//父组件中的引用
<Child v-if="isShow" :airportId="isShow" />
//这里的isShow是一个字符串,有值则为true,无值为false
子组件:
props: {
airportId: {
type: String,
default: ''
}
},
watch: {
airportId (val) { //这里监听到有值调用相关的接口
if (val) {
this.getUavInfo()
}
}
},
上述代码块的问题是当isShow变化时可以被监听到,但第一次变化不会被监听到,举个例子: 也就是说当isShow从空字符变成t001时是监听不到的,但从t001变成t002是可以监听到的。
解决办法
- 第一种,把父组件中的v-if改为v-show即可
- 第二种,把父组件中的v-if="isShow"去掉,写在子组件最外层的div上
其中的原理
原来的代码之所以有问题是和vue页面的初始化函数有关,这里的初始化函数不是指vue的生命周期,这里指的是vue源码中的initState(vm)函数,如下图
这里的初始化顺序是:beforeCreate ->inject -> Props -> Methods -> Data -> Computed -> Watch ->provide-> created
跟我上述代码的错误有关系的就是props和watch,从这里可以看到是先初始化props之后才初始化的watch,所以当我把v-if写在父组件中的时候就会出问题的,因为isShow本来是'',当它变成t001的时候才加载子组件,这时候由于props先初始化了,所以子组件接收到的值就是t001,但这时候watch还没有初始化,所以是监听不到的,当再次改变isShow的才会被检测到。
- 那为什么父组件中的v-if改为v-show没问题呢,这是因为v-show时组件一直存在,那isShow首次变化之前子组件的props和watch都是初始化好的,那当然可以监听到了。
- 把v-if移到子组件中可以的原理和v-show类似,子组件被引入父组件就已经初始化好了props和watch,这里v-if是在子组件初始化后才生效的,所以当然也可以监听到了
总结
大概就是这么个情况,问题其实不难,最重要的把其中的逻辑搞清楚了。