Vue 3 中可通过 provide/inject 传递模板 ref 实现跨层级 DOM 访问:父组件用 provide('key', ref) 暴露 ref 对象,子组件 inject 获取后通过 .value 安全访问 DOM,需配合 onMounted 或 watchEffect 使用,并注意 SSR 判空与只读原则。

在 Vue 3 的组合式 API 中,Inject 本身不直接提供 DOM 引用,它只负责跨层级传递响应式数据或函数。要让深层子组件拿到父组件的 DOM 元素(比如一个容器 <div ref="container">),核心思路是:父组件把绑定到 DOM 的 ref(即模板 ref)通过 provide 注入,子组件用 inject 接收并使用。
父组件:用 provide 暴露模板 ref
模板 ref 是一个响应式引用对象(Ref<htmlelement null></htmlelement>),需确保它在 setup 中被正确创建、绑定,并通过 provide 传下去。
- 在
setup()中声明 ref:const containerRef = ref<htmlelement null>(null)</htmlelement> - 在模板中绑定:
<div ref="containerRef">...</div> - 调用
provide时传 ref 对象本身(不是 .value):provide('containerRef', containerRef)
深层子组件:用 inject 获取并安全使用 ref
子组件注入后得到的是同一个 ref 对象,可读取其 .value 获取真实 DOM 元素,但要注意时机和空值判断。
- 注入:
const containerRef = inject<ref null>>('containerRef')</ref> - 访问 DOM:
if (containerRef?.value) { containerRef.value.focus() } - 推荐配合
onMounted或watchEffect监听变化,避免在 DOM 尚未挂载时读取.value为 null
进阶技巧:封装成可复用的 provide/inject 组合
为避免硬编码 key 和类型重复,可以封装成函数:
- 定义 symbol key:
export const ContainerRefKey = Symbol('ContainerRef') - 父组件调用:
provide(ContainerRefKey, containerRef) - 子组件注入:
const containerRef = inject<ref null>>(ContainerRefKey)</ref> - 好处:类型安全、避免命名冲突、便于统一维护
注意事项与常见陷阱
这个模式看似简单,但几个细节容易出错:
- 不能注入 .value:必须注入 ref 对象,否则失去响应性,子组件无法感知 DOM 挂载/卸载
-
父组件 ref 必须已绑定:如果父组件模板中漏写
ref="xxx",注入的 ref 始终为 null - 子组件不能修改 ref.value:虽然技术上可行,但会破坏父组件对 DOM 的控制权,应只读使用
-
SSR 场景下需判空:服务端渲染时 DOM 不存在,
ref.value一定为 null,务必加防御性检查

















