一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
前述:
v-if涉及的生命周期问题
今天维护项目的时候发现两个问题。第一个是在dialog外部获取组件ref里的方法并执行,执行之后将展示dialog以及dialog内部内容的条件进行改变,从true变更为false,并且将执行刷新函数,但是发现刷新函数handleRefresh一直没有被执行,于是查看了很久的问题。
见以下代码:
业务组件的代码
其中done方法是一个关闭dialog的方法,也就是说会将dialog组件内部的dialog变量设为false,而这个dialog的变量跟active进行了双向数据绑定。所以一旦执行submit方法,active变量会为false。
而DetailRef.submit方法在请求完所需数据之后,会抛出一个refresh事件,从而被Detail组件中的@refresh的监听函数监听到,进而执行handleRefresh方法
<Dialog
v-model="active"
width="30%"
@submit="
(done) => {
done(); //将active置为false
$refs.DetailRef.submit() // submit是一个返回promise的函数
}
"
>
<Detail
:detail="detailTable"
v-if="active"
@refresh="handleRefresh"
ref="DetailRef"
></Detail>
</Dialog>
dialog组件内部代码
<el-dialog
:visible.sync="dialog"
>
<div>
<div>
<slot> content </slot>
</div>
</div>
<div class="dialog__footer" v-if="showFooter">
<el-button @click="beforeClosed">关闭</el-button>
<slot name="footer" :done="setValue">
<el-button
v-if="!disabled"
@click="submit"
type="primary"
>提交</el-button
>
</slot>
</div>
</el-dialog>
点击提交之后发生的事情: 你会发现当你点击提交按钮之后执行submit方法之后,active将被置为false,从而Detail组件的dom节点也会被移除掉。同时会如前面所说发起一个请求并在得到响应之后抛出一个refresh事件,外层的Detail组件监听这个事件进而执行handleRefresh方法。但是从submit方法执行到改变active再到执行请求,这都是一个同步的过程,而handleRefresh的执行时机则是拿到响应并且抛出refresh事件之后,并且Detail组件上有一个v-if,条件却是active。
回过头来看看问题,问题是执行submit之后,handleRefresh没有被执行,为什么呢?
答案现在很明显了,就是因为submit方法修改active是一个同步的过程,而handleRefresh却需要拿到事件之后才能执行,而事件可能还没有抛出,Detail的v-if条件就被置为false了,从而整个Dom节点都被移除文档外,并且事件也被卸载了,这样的话,即使事件被emit了,但是元素节点已经从页面中移除了,注册的监听函数也就不会被触发了。