错误的预判: watch(immediate)只有在openDialog事件执行之后,v-model变为true的时候才会执行回调。
一、watch(immediate)的执行时机
| 阶段 | 发生的事 |
|---|---|
| setup | 创建响应式、watch、computed |
| watch(immediate) | 就在 setup 过程中执行 |
| render | 读取 template 表达式 |
| beforeMount | 准备挂载 |
| mounted | DOM 已经插入 |
👉 watch(immediate) 比 render 还早
所以:
- 它不受 v-if 影响
- 它也不等 DOM
下面的行为都不受组件内部的v-if的影响
| 行为 | 执行阶段 |
|---|---|
| watch(immediate) | setup |
模板中 {{ xxx }} 被访问 | render 阶段 |
| v-for source 被读取 | render 阶段 |
二、组件内部的v-if和组件外部的v-if的本质区别
情况 A:v-if 在组件外部(控制组件是否存在)
<Child v-if="show" />
show === false 时:
| 项目 | 是否发生 |
|---|---|
| 创建组件实例 | ❌ |
| 执行 setup | ❌ |
| 注册 watch | ❌ |
| render template | ❌ |
| 读取任何表达式 | ❌ |
👉 Child 在运行期完全不存在
情况 B:v-if 在组件内部(控制局部渲染)
<template>
<div v-if="show">
{{ foo }}
</div>
</template>
show === false 时:
| 项目 | 是否发生 |
|---|---|
| 创建组件实例 | ✅ |
| 执行 setup | ✅ |
| watch(immediate) | ✅ |
| render() 调用 | ✅ |
读取 foo | ❌(因为分支不走) |
👉 组件存在,但该分支在 render 中被跳过
结论
- 外部的v-if,整个组件的实例都不存在,setup阶段都不会执行
- 内部的v-if, 只有v-if的部分的render不会执行,其余的操作都会执行。
vue首次渲染
Vue 3 组件首次渲染完整时间线
| 顺序 | 官方钩子 / 阶段 | 发生的事 |
|---|---|---|
| 1 | setup | 初始化状态、注册 watch / computed |
| 2 | watch(immediate) | 在 setup 执行期间立即触发 |
| 3 | render(内部) | 执行 render 函数,读取 template 表达式 |
| 4 | onBeforeMount | DOM 挂载前 |
| 5 | mount(内部过程) | 创建并插入真实 DOM |
| 6 | onMounted | DOM 已插入页面 |
👉 这里的「mount」是内部过程,不是钩子