前言:不小心发现线上一个bug,看了下代码,了解到因为用Vue.nextTick的场景不对,在此做个记录。
一、bug重现
具体场景是,修改文件夹名称时,弹出一个修改名称的弹出框
此时文件名“啦啦啦”会带到编辑文件夹的弹出框中。修改保存后,文件名变成“啦啦啦123”,然后再次修改文件夹名,结果:
此时为什么文件名没有带过去?
二、代码逻辑
通过查看代码了解到 编辑文件夹 弹出框是一个子组件,父组件触发修改文件名的事件时,通过 folderToBeRenamed 传递新的数据
this.$nextTick(() => {
this.folderToBeRenamed = newFolderName
})
子组件再通过props 获取 folderToBeRenamed
并用 watch 监听
watch: {
folderToBeRenamed () {
this.folderName = this.folderToBeRenamed.folder_name
}
}
folderName就是子组件要获取的数据,看起来好像有道理,可是为什么只起到一次监听作用?通过调试发现,只有第一次点击修改文件名,watch里的事件会执行;后续不管folderToBeRenamed是否改变都不会执行watch里的事件了。
三、了解Vue.nextTick()
先看下官网的解释
有点难懂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()用法也不太熟,所以在此记录,谨防踩坑_(:з」∠)_
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。