ref 初始化为 null 是设计使然,因 dom 未生成时无对象可指;其赋值严格发生在 onmounted 钩子中,v-if、异步组件等场景下需额外监听条件或使用 ref 数组。

因为 DOM 元素在组件挂载前根本不存在,ref 只是“占位符”,它不会主动创建节点,只在真实 DOM 渲染完成后才被 Vue 自动赋值。
ref 初始化为 null 是设计使然
声明 const elRef = ref(null) 本质是创建一个响应式容器,初始值设为 null 有三重考虑:
-
逻辑诚实:DOM 尚未生成,此时没有可指向的对象,
null是最准确的状态表达 -
类型安全:TypeScript 能据此推导出
elRef.value: HTMLElement | null,强制开发者做空值检查 -
响应式基础:Vue 需要监听这个引用的变更——从
null到真实元素的过程,本身就是一次关键响应式更新
生命周期决定 ref 何时“活”过来
ref.value 的赋值不是随机发生的,它严格绑定在组件渲染流程中:
-
setup 执行时:模板还没解析,DOM 还在内存里构型,ref.value 必为
null -
onBeforeMount 触发时:虚拟 DOM 已就绪,但尚未挂载到真实 DOM 树,ref.value 仍为
null -
onMounted 触发时:真实 DOM 已插入文档,Vue 完成 ref 绑定,此时
elRef.value才首次指向有效节点
v-if、异步、v-for 会让 ref 更“晚熟”
即使组件已 mounted,ref 也可能暂时为 null,常见于以下场景:
-
v-if 初始为 false:对应 DOM 根本没创建,ref 自然无从绑定;需等条件变为 true 后再操作,或用
watch监听条件变化 -
异步组件或 Suspense:子组件加载完成前,其内部 ref 不会初始化;应在
onActivated或加载回调中处理 -
v-for 渲染列表:单个 ref 无法覆盖多个节点,应改用
ref数组(如ref="itemRefs"),并在onUpdated中确认批量 ref 已同步
正确访问方式:时机 + 防御
安全读取 ref 的核心是两步走——卡准时机、兜住空值:
- 所有 DOM 操作逻辑统一收口到
onMounted(或onActivated,若组件被 keep-alive) - 调用前必加防护:
elRef.value?.focus()或if (elRef.value) { ... } - 调试时可打印生命周期钩子顺序:
console.log('mounted', elRef.value)对比 setup 里的日志,直观验证时机









