$refs在非H5平台常为undefined,因小程序无DOM、渲染层与逻辑层分离,且uni-app限制其仅能获取自定义组件实例;Vue2需用onReady+uni.nextTick并做存在性判断,Vue3必须通过defineExpose显式暴露。

ref 在 uni-app 中能获取子组件实例,但**是否成功取决于平台、Vue 版本和调用时机**。H5 端基本可靠;微信小程序、App 等非 H5 端,$refs 在 Vue2 和 Vue3 下行为差异大,且容易返回 undefined。
为什么 $refs 在非 H5 平台经常是 undefined
uni-app 官方明确说明:ref 属性在非 H5 平台(如微信小程序)**不保证能直接访问子组件实例**,底层渲染机制不同,this.$refs.xxx 可能为空或为普通节点对象而非 Vue 实例。
- Vue2 项目中,
$refs有时能取到,但不稳定——尤其在onLoad或created阶段就访问,大概率失败 - Vue3(
setup+defineExpose)必须显式暴露方法,否则即使拿到实例也调不到内部函数 - 小程序原生组件(如
cover-view、自定义 tabbar)完全不支持ref获取 Vue 实例
Vue2 项目中安全获取子组件实例
必须等组件真正挂载完成,并做存在性判断:
- 用
onReady(而非onLoad或mounted)——这是 uni-app 小程序端最可靠的生命周期钩子 - 配合
uni.nextTick确保 DOM 和组件树已就绪 - 每次调用前检查
this.$refs.xxx是否存在,再检查方法是否为函数
onReady() {
uni.nextTick(() => {
const child = this.$refs.childRef;
if (child && typeof child.doSomething === 'function') {
child.doSomething('hello');
}
});
}
Vue3 项目中必须 defineExpose
Vue3 的 setup 默认不暴露任何内容,$refs 拿到的实例是空壳。子组件必须主动声明哪些方法/数据可被父组件访问:
- 子组件内使用
defineExpose({ doSomething, data }) - 父组件仍通过
ref绑定 +this.$refs.xxx(选项式)或ref响应式变量(组合式)获取 - 注意:Vue3 的
ref在模板中写法不变,但 JS 层需用ref()创建响应式引用变量来接收
// 子组件 Child.vue
<script setup>
const doSomething = (msg) => console.log(msg);
defineExpose({ doSomething });
</script>
v-for 渲染多个子组件时 ref 怎么写
固定字符串 ref="item" 会导致所有子组件覆盖同一个 key,this.$refs.item 只返回最后一个。必须动态绑定:
- 写成
:ref="el => { if (el) $refs.list.push(el) }"(Vue3 组合式推荐) - 或 Vue2 中用
:ref="'item' + index",然后遍历Object.keys(this.$refs)找匹配项 - 更稳妥的做法:给每个子组件加唯一
id属性,用this.selectComponent('#id')替代$refs(全平台兼容)
真正跨端稳定的方式不是死磕 $refs,而是用 this.selectComponent + $vm——它绕过 Vue 层,直取小程序组件实例,再通过 $vm 访问其 Vue 实例属性。这点常被忽略,却是小程序端最可靠的方案。


















