Appearance
大多数时候你用 Vue 的数据绑定就够了。但偶尔你需要直接操作 DOM 元素——比如让输入框自动聚焦、获取滚动位置、操作 canvas 画布。 这时就用 ref 属性配合 $refs。
获取 DOM 元素
vue
<template>
<input ref="inputRef" type="text" placeholder="我会自动获得焦点">
<button @click="focusInput">手动聚焦</button>
</template>
<script>
export default {
methods: {
focusInput() {
this.$refs.inputRef.focus() // 直接操作 DOM
}
}
}
</script>
步骤:
- 在元素上加
ref="名字" - 在 JavaScript 中用
this.$refs.名字获取这个元素 - 然后就能调用原生 DOM 方法了(
focus()、scrollIntoView()等)
访问时机 — mounted
$refs 在组件挂载完成后才可用。如果在 data 或 created 里访问,拿到的是 undefined。
vue
<script>
export default {
mounted() {
this.$refs.inputRef.focus() // ✅ 这里可以
},
created() {
// this.$refs.inputRef → undefined ❌ 太早了
}
}
</script>
📝 Note:组件的生命周期顺序data 初始化 → created(数据有了,DOM 还没)→ mounted(DOM 渲染完了) $refs 要到 mounted 之后才能用。
在 v-for 中获取多个元素
在 v-for 的元素上使用 ref,$refs 会返回一个数组:
vue
<template>
<ul>
<li v-for="item in list" :key="item" ref="items">{{ item }}</li>
</ul>
</template>
<script>
export default {
data() {
return { list: ['A', 'B', 'C'] }
},
mounted() {
console.log(this.$refs.items) // [li, li, li]
}
}
</script>
⚠️ Warning:注意顺序v-for 中 ref 数组的顺序不一定和列表顺序一致,取决于你的 :key 和数据变化。不要依赖它们的顺序来做业务逻辑。
获取组件实例
ref 不仅能获取 DOM 元素,还能获取子组件实例:
vue
<template>
<ChildComponent ref="childRef" />
<button @click="callChildMethod">调用子组件方法</button>
</template>
<script>
export default {
methods: {
callChildMethod() {
this.$refs.childRef.doSomething() // 调用子组件的方法
}
}
}
</script>
这样就能"父组件主动调用子组件的方法"。不过这种方式不建议频繁使用,尽量通过 props 和 events 来通信。
什么时候需要直接操作 DOM?
Vue 的"响应式"已经覆盖了 95% 的情况。以下场景才需要 $refs: | 场景 | 示例 | | 聚焦输入框 | refs.xxx.focus() | | 获取元素尺寸/位置 | refs.xxx.getBoundingClientRect() | | Canvas 操作 | refs.canvas.getContext('2d') | | 集成第三方 DOM 库 | 如 Chart.js、Swiper | | 播放控制(视频/音频) | refs.video.play() |
新手常见问题
Q:为什么我的 this.$refs.xxx 是 undefined? A:最常见的原因是在 mounted 之前访问了。确保你的代码在 mounted 或之后(如按钮点击时)调用。 Q:ref 能在组件内部用吗? A:能。组件内任何元素都能用 ref 标记,只要是这个组件渲染的就能通过 this.$refs 访问。 Q:ref 和 v-bind(:value)有什么区别? | | v-bind(数据绑定) | ref(模板引用) | | 做什么 | 把数据绑定到属性或 prop | 获取 DOM 元素或组件实例 | | 数据流 | JS → 模板(声明式) | 模板 → JS(命令式) | | 典型场景 | :value="msg" 显示数据 | ref="input" 然后 focus() | | 何时可用 | 任何时刻 | 只能在 mounted 之后 |
v-bind是声明式的:你说"数据是什么,模板就渲染什么",Vue 帮你搞定ref是命令式的:你拿到元素自己操作,就像用document.querySelector
能用
v-bind解决的,优先用v-bind。ref只在你需要突破数据绑定限制(比如调用 DOM 方法)时才用。 下一步: 💡 Tip:Composition API 写法(Vue 3)
vue
<script setup>
import { ref, onMounted } from 'vue'
const inputRef = ref(null)
onMounted(() => { inputRef.value?.focus() })
</script>
组合式 API 中 ref 的变量名要和模板中 ref="inputRef" 的名字一致。 详见: