踩坑日记:生命周期问题

163 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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了,但是元素节点已经从页面中移除了,注册的监听函数也就不会被触发了。