添加按钮活蹦乱跳,子组件的Mounted 却装死?Vue 子组件的生命周期探秘!

  • 父组件 index.vue,使用子组件 ave-form.vue。
  • 子组件 ave-form.vue,负责添加、查看、编辑、表单的显示。点击父组件中的添加按钮,子组件中的Mounted函数没有执行 !!!

“点击添加没反应?Vue 子组件 Mounted 之谜大揭秘!”

作者:小丁 | 日期:2025-03-04

嘿,各位前端探险家 ‍‍!今天我们要一起破解一个让人抓狂的小谜题:为什么我在 Vue 子组件里辛辛苦苦写的 mounted(),点击“添加”按钮时就是不打印日志? 是代码叛变了,还是我打开方式不对?别急,带上你的咖啡 ☕,跟着我一起抽丝剥茧,揭开这个“生命周期失踪案”的真相!


案件背景:失踪的 mounted

想象一下,你是一个前端侦探,接到一个紧急任务:有个 Vue 项目,子组件 mounted() 死活不执行。代码是这样的:

mounted() {
  console.log('Initial form.sampleSendTime:', this.form.sampleSendTime);
}

你信心满满地点击“添加”按钮,期待控制台跳出 2025-03-04T07:27:26.058Z(一个帅气的 ISO 时间戳)。结果呢?一片寂静,控制台冷漠得像冬天的北极 ❄️。这到底是怎么回事?让我们从犯罪现场(代码)开始调查吧!


️‍♂️ 调查第一步:父组件的“作案动机”

先来看看父组件怎么调用这个子组件的(src/views/tools/fake-strategy/index.vue):

<ave-form
  :clist="clist.admins"
  :value="aveForm"
  :visible="aveFormVis"
  :operate-type="operateType"
  @close="onAveFormClose"
/>

“添加”按钮的逻辑是这样的:

public handleAdd() {
  this.aveForm = Object.assign({}, {});
  this.aveFormVis = true;
  this.operateType = 'add';
}

乍一看,好像没啥问题啊!点击“添加”,aveFormVis 变成 true,子组件的对话框()应该弹出,mounted 也应该触发,对吧? 但真相往往藏在细节里。注意到了吗?这里没有 v-if,子组件是始终存在于 DOM 中的,只是通过 :visible 控制显示与否。这是个关键线索!


️‍♀️ 调查第二步:子组件的“不在场证明”

子组件 用的是 Element UI 的

<el-dialog
  :visible="visible"
  :before-close="handleTopRightClose"
  destroy-on-close
  ...
>
  • :visible="visible":从父组件的 aveFormVis 绑定过来,控制对话框开关。
  • destroy-on-close:关闭时销毁对话框内部内容,下次打开时重新创建。

理论上,destroy-on-close 应该让子组件在关闭后销毁,点击“添加”时重新挂载,触发 mounted。但等等!我们发现,destroy-on-close 只影响 内部的 DOM 和状态,并不会销毁整个 组件实例。换句话说, 就像个“僵尸组件” ‍♂️,一直活着,只是藏起来了!


SVG 插图:组件生命周期的“僵尸状态”

为了让大家更直观地理解,我用 SVG 画了个图:

父组件加载 创建 mounted() 触发一次 点击“添加”只是更新 :visible mounted() 不触发!
<svg width="400" height="200" xmlns="http://www.w3.org/2000/svg">
  <rect x="50" y="20" width="300" height="160" fill="#f0f0f0" stroke="#666" stroke-width="2"/>
  <text x="60" y="40" font-size="16" fill="#333">父组件加载text>
  <circle cx="90" cy="80" r="20" fill="#ff9999"/>
  <text x="70" y="85" font-size="12" fill="#fff"><ave-form> 创建text>
  <text x="120" y="80" font-size="14" fill="#333">mounted() 触发一次text>
  <path d="M 110 80 Q 200 120 290 80" stroke="#666" stroke-width="2" fill="none"/>
  <text x="180" y="140" font-size="14" fill="#666">点击“添加”只是更新 :visibletext>
  <text x="180" y="160" font-size="14" fill="#ff0000">mounted() 不触发!text>
svg>

这个图展示了: 在父组件初次渲染时就挂载了,mounted 只执行一次。之后点击“添加”,只是让对话框可见,组件实例没销毁,也没重新挂载。


真相大白:Vue 生命周期的“冷知识”

经过一番侦查,我们锁定了“凶手”:

  • 子组件在父组件渲染时已挂载:没有 v-if 在页面加载时就创建,mounted 在那时就执行了。
  • 点击“添加”只是 Prop 更新aveFormVisfalse 变为 true,只是改变了 :visible,没有触发重新挂载。
  • destroy-on-close 的误解:它只销毁对话框内部内容, 的 Vue 实例依然存活。

简单来说,你期待的“每次打开都触发 mounted”被 Vue 的生命周期规则无情打破了!


️ 破案方案:让 mounted 重获新生

别慌,我们有办法让 mounted 在点击“添加”时复活!以下是几个“解药”:

方案 1:用 v-if 给组件“断电重启” ⚡

修改父组件:

<ave-form
  v-if="aveFormVis"
  :clist="clist.admins"
  :value="aveForm"
  :visible="aveFormVis"
  :operate-type="operateType"
  @close="onAveFormClose"
/>
  • 效果v-ifaveFormVisfalse 时销毁,为 true 时重新创建。每次点击“添加”,mounted 都会开心地跳出来喊:“我又活了!”

方案 2:监听 visible,曲线救国

如果不想改父组件,可以在子组件加个“眼线”:

@Watch('visible')
watchVisible(newVal: boolean) {
  if (newVal) {
    console.log('Dialog opened, Initial form.sampleSendTime:', this.form.sampleSendTime);
  }
}
  • 效果:对话框打开时,代替 mounted 打印日志。简单粗暴,但够用!

方案 3:手动检查状态,稳扎稳打 ️

mounted 加个条件:

mounted() {
  if (this.visible) {
    console.log('Initial form.sampleSendTime:', this.form.sampleSendTime);
  }
}
@Watch('visible')
watchVisible(newVal: boolean) {
  if (newVal) {
    console.log('Initial form.sampleSendTime:', this.form.sampleSendTime);
  }
}
  • 效果:确保每次打开对话框都能打印,哪怕组件是“僵尸”状态。

结局:胜利的喜悦

经过这场技术侦探之旅,我们不仅找回了失踪的 mounted(),还学到了 Vue 组件生命周期的一个小秘密:挂载不是你想触发就能触发的,得看组件有没有“重生”机会!用 v-if 是最直接的解法,就像给组件按了个“重启键” 。

试试方案 1,点击“添加”,控制台会欢快地输出:

Initial form.sampleSendTime: 2025-03-04T07:27:26.058Z

怎么样,是不是有种破案成功的成就感? 下次遇到类似问题,别忘了检查组件是不是“僵尸”状态哦!


彩蛋:生活化比喻

想象成一个“智能灯泡” :

  • 没用 v-if:灯泡一直插着电,开关只是控制亮不亮,装灯泡的动作(mounted)只发生一次。
  • v-if:每次要亮时都重新插电,装灯泡的仪式感满满,每次都触发!

好了,今天的探险就到这里!有什么前端迷案困扰着你?评论区告诉我,我带着放大镜 来帮你破解!✌️


你可能感兴趣的:(产品资质管理系统,vue2)