v-if遇到setTimeout(() => {emit(‘xxx’)},0)
-
一个例子
-
当我们需要在父子组件间通信时候,我们需要使用emit -
子组件 setup(props,{emit}){
function handleClick(){
emit('XXX')
}
}
这时当子组件中触发了点击事件,调用handleClick函数之后,将会发送自定义事件XXX到父组件 -
父组件 <SubComponent v-if="isVisblie" @XXX="onSubClick" v-click-outside="handleClickOutside">
</SubComponent>
...
function handleClickOutside(){
this.isVisblie = false
}
function onSubClick(){
console.log('ok')
}
父组件会调用onSubClick方法,打印出 ok -
当这个例子中子组件使用了setTimeout
-
子组件 setup(props,{emit}){
function handleClick(){
setTiemout(() => {emit(XXX)},0)
}
}
这时将emit放入setTimeout中,将会在下轮事件循环中emit出这个自定义事件XXX -
父组件 <SubComponent v-if="isVisblie" @XXX="onSubClick" v-click-outside="handleClickOutside">
</SubComponent>
...
function handleClickOutside(){
this.isVisblie = false
}
function onSubClick(){
console.log('ok')
}
由于存在v-click-outside,而子组件中的点击事件会出发clickoutside,所以在本轮事件循环结束之前,SubComponent已经被销毁了,所以自定义事件XXX的处理函数也就无法执行 -
为什么不加setTimeout就可以正常执行
-
首先我们回顾一下Vue的异步更新队列
-
异步更新队列如何解释上面的错误
- 当没有在子组件中加入setTimeout的时候,emit方法将在本轮事件循环中执行,这时,虽然触发emit的点击事件虽然已经将isVisblie更改为false,但是Vue会将销毁SubComponent放入异步更新队列,所以当emit被触发的时候SubComponent还没有被销毁。
- 当在子组件中加入setTimeout的时候,emit方法将在作为宏任务被放入宏任务队列,将在下一次的事件循环开始时被主线程取出放入执行栈执行,而这时异步更新队列中的销毁SubComponent的操作已经被执行,所以在emit方法被调用的时候,SubComponent已经不存在了。
|