Vue 中如何获取 DOM?
在 Vue 中获取 DOM 元素,最推荐且最常用的方法是使用 ref 属性。
虽然 Vue 是声明式的(数据驱动视图),但在某些场景下(如集成第三方库、管理焦点、Canvas 绘图等),我们确实需要直接操作 DOM。
以下是针对 Vue 3 和 Vue 2 的具体实现方式:
1. Vue 3 (<script setup> 组合式 API)
在 Vue 3 中,获取 DOM 需要声明一个与模板中 ref 属性同名的响应式变量。
步骤:
- 在模板元素上添加
ref="xxx"。 - 在脚本中创建一个同名的
ref变量,初始值为null。 - 在
onMounted生命周期钩子中访问(必须等待组件挂载完成,DOM 才存在)。
plaintext
<template>
<!-- 1. 绑定 ref 名称 -->
<input type="text" ref="myInput" />
<button @click="focusInput">聚焦</button>
</template>
<script setup>
import { ref, onMounted } from 'vue'
// 2. 声明同名变量,初始值为 null
const myInput = ref(null)
// 3. 在生命周期钩子中访问
onMounted(() => {
// 注意:DOM 元素在 .value 中
console.log(myInput.value)
myInput.value.focus()
})
const focusInput = () => {
// 在事件处理中也可以访问
myInput.value.focus()
}
</script>
2. Vue 2 (选项式 API)
在 Vue 2 中,所有的 ref 都会被注册到 this.$refs 对象上。
步骤:
- 在模板元素上添加
ref="xxx"。 - 在
mounted钩子或方法中通过this.$refs.xxx访问。
plaintext
<template>
<div>
<div ref="myBox">这是一个盒子</div>
</div>
</template>
<script>
export default {
mounted() {
// 访问 DOM
const element = this.$refs.myBox
console.log(element)
element.style.color = 'red'
}
}
</script>
3. 特殊情况与注意事项
A. 在 v-for 循环中使用 ref
- Vue 2:
this.$refs.xxx会自动变成一个数组,包含循环出来的所有元素。 - Vue 3: 需要绑定一个函数来收集元素,或者使用数组类型的 ref。
plaintext
<!-- Vue 3 v-for 获取 DOM 示例 -->
<template>
<ul>
<li v-for="item in list" :key="item" :ref="(el) => setItemRef(el)">
{{ item }}
</li>
</ul>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const list = [1, 2, 3]
const itemRefs = ref([])
// 将元素推入数组
const setItemRef = (el) => {
if (el) {
itemRefs.value.push(el)
}
}
onMounted(() => {
console.log(itemRefs.value) // 包含所有 li 元素的数组
})
</script>
B. 获取组件实例 vs 获取 DOM
如果 ref 绑定的是一个子组件(而不是原生 HTML 标签):
- Vue 2:
this.$refs.child获取的是子组件实例(可以使用this.$refs.child.$el获取该组件的根 DOM)。 - Vue 3:
myRef.value获取的是子组件实例。如果想获取该组件内部的 DOM,通常需要子组件通过defineExpose暴露特定的 DOM,或者直接访问$el(不推荐直接依赖$el,建议组件间通信)。
C. 为什么不能在 created 中获取?
在 created 阶段,Vue 实例已经初始化,但 DOM 还没有被渲染和挂载。必须在 mounted 生命周期之后才能获取到真实的 DOM 元素。
总结
| 方式 | 语法 | 关键点 |
|---|---|---|
| Vue 3 | const el = ref(null) |
访问时用 el.value,变量名必须与模板 ref 一致 |
| Vue 2 | this.$refs.el |
直接通过 $refs 对象访问 |
| 原生 JS | document.querySelector |
不推荐。破坏了 Vue 的封装性,且容易产生时序问题 |