10

前言:不小心发现线上一个bug,看了下代码,了解到因为用Vue.nextTick的场景不对,在此做个记录。

一、bug重现

具体场景是,修改文件夹名称时,弹出一个修改名称的弹出框

clipboard.png

此时文件名“啦啦啦”会带到编辑文件夹的弹出框中。修改保存后,文件名变成“啦啦啦123”,然后再次修改文件夹名,结果:

clipboard.png

此时为什么文件名没有带过去?

二、代码逻辑

通过查看代码了解到 编辑文件夹 弹出框是一个子组件,父组件触发修改文件名的事件时,通过 folderToBeRenamed 传递新的数据

this.$nextTick(() => {
   this.folderToBeRenamed = newFolderName
})

子组件再通过props 获取 folderToBeRenamed

并用 watch 监听

watch: {
    folderToBeRenamed () {
      this.folderName = this.folderToBeRenamed.folder_name
    }
 }

folderName就是子组件要获取的数据,看起来好像有道理,可是为什么只起到一次监听作用?通过调试发现,只有第一次点击修改文件名,watch里的事件会执行;后续不管folderToBeRenamed是否改变都不会执行watch里的事件了。

三、了解Vue.nextTick()

先看下官网的解释

clipboard.png

有点难懂o(╯□╰)o

看到知乎上的解释:

HTML: <div id="testCount" v-html="message"></div>

//改变数据
vm.message = 'changed'

//想要立即使用更新后的DOM。这样不行,因为设置message后DOM还没有更新
console.log(document.getElementById('testCount').innerHTML) // 并不会得到'changed'

//这样可以,nextTick里面的代码会在DOM更新后执行
Vue.nextTick(function(){
    console.log(document.getElementById('testCount').innerHTML) //可以得到'changed'
})

所以 vue的nextTick的作用类似setTimeout,再添加一个新的空的异步事件,执行完异步事件后调用callback。

所以回到我们前面的bug,可以明白,子组件只感受到folderToBeRenamed的一次变化,就相当于for循环里的setTimeout

for(var i = 0; i < 3; i++) {
   setTimeout(function() {
       console.log('timeout' + i);
   })
}

最后输出的i都是3,也就是只能感受到i从0变为3 这次变化。

四、修改bug

这里的逻辑本来是比较简单的,父组件传值,子组件直接获取就可以了。为什么需要父组件用Vue.nextTick(),子组件用watch监听,我也不太清楚。因为自己对Vue.nextTick()用法也不太熟,所以在此记录,谨防踩坑_(:з」∠)_


eraser123
483 声望24 粉丝

^_^你在看我?更多相关: