Skip to content
On this page

大多数时候你用 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>

步骤:

  1. 在元素上加 ref="名字"
  2. 在 JavaScript 中用 this.$refs.名字 获取这个元素
  3. 然后就能调用原生 DOM 方法了(focus()scrollIntoView() 等)

访问时机 — mounted

$refs 在组件挂载完成后才可用。如果在 datacreated 里访问,拿到的是 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:refv-bind:value)有什么区别? | | v-bind(数据绑定) | ref(模板引用) | | 做什么 | 把数据绑定到属性或 prop | 获取 DOM 元素或组件实例 | | 数据流 | JS → 模板(声明式) | 模板 → JS(命令式) | | 典型场景 | :value="msg" 显示数据 | ref="input" 然后 focus() | | 何时可用 | 任何时刻 | 只能在 mounted 之后 |

  • v-bind声明式的:你说"数据是什么,模板就渲染什么",Vue 帮你搞定
  • ref命令式的:你拿到元素自己操作,就像用 document.querySelector

能用 v-bind 解决的,优先用 v-bindref 只在你需要突破数据绑定限制(比如调用 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" 的名字一致。 详见: