在 Vue 中,获取 DOM 节点是通过 ref
特性来实现的。直接操作 DOM 不是 Vue 推荐的首选方式(Vue 提倡声明式渲染和数据驱动),但在某些特定场景下(如触发焦点、测量元素尺寸、集成第三方库等)仍然需要访问原生 DOM 元素。
核心方法:使用 ref
- 在模板中定义
ref
:
在你想要获取的 HTML 元素上添加ref
属性,并为其指定一个唯一的名称。 - 在组件实例中通过
$refs
访问:
在组件的mounted
或其他生命周期钩子及方法中,通过this.$refs.名称
来访问对应的 DOM 节点。
详细示例
基本用法
<template>
<div>
<!-- 为 input 元素绑定 ref -->
<input ref="myInput" type="text" placeholder="Hello Vue!" />
<button @click="focusInput">聚焦输入框</button>
</div>
</template>
<script>
export default {
methods: {
focusInput() {
// 通过 $refs 获取 DOM 元素并调用其 focus 方法
this.$refs.myInput.focus();
}
},
mounted() {
// DOM 已经渲染完成,可以安全地访问 $refs
console.log(this.$refs.myInput); // 输出: <input> 元素
}
}
</script>
重要注意事项
- 时机问题:
this.$refs
只在组件挂载后 (mounted
) 才可用。- 在
created
钩子中,DOM 尚未生成,this.$refs
会是undefined
。 - 如果元素是通过
v-if
动态渲染的,那么只有当v-if
为true
时,$refs
才存在。
ref
的值取决于绑定的目标:- 绑定到原生 HTML 元素上:
$refs.xxx
是原生的 DOM 元素。 - 绑定到子组件上:
$refs.xxx
是子组件的 Vue 实例,而不是它的根 DOM 元素。
- 绑定到原生 HTML 元素上:
v-for
中的ref
:- 当
ref
用在v-for
内部时,$refs.xxx
将是一个包含所有对应 DOM 节点或组件实例的数组。
<li v-for="item in list" :key="item.id" ref="listItems">{{ item.name }}</li> // this.$refs.listItems 是一个包含所有 <li> 元素的数组
- 当
$refs
不是响应式的:this.$refs
对象本身不会触发视图更新。它只是一个方便访问的属性集合。
- Vue 3 Composition API (setup):
- 在
<script setup>
中,需要使用ref()
函数创建一个响应式引用。
<script setup> import { ref, onMounted } from 'vue' // 创建一个 ref 引用 const myInput = ref(null) function focusInput() { // 通过 .value 访问 DOM 元素 myInput.value.focus() } onMounted(() => { console.log(myInput.value) // DOM 元素 }) </script> <template> <input ref="myInput" type="text" /> <button @click="focusInput">聚焦</button> </template>
- 在
替代方案(更 Vue 化的方式)
虽然 ref
是获取 DOM 的标准方法,但应优先考虑以下更符合 Vue 理念的方式:
- 使用
v-model
:对于表单元素,尽量使用v-model
进行双向绑定,而不是手动操作value
。 - 通过
props
和events
通信:避免直接访问子组件的 DOM,而是通过传递数据和触发事件来交互。 - 计算属性和侦听器:用数据变化驱动视图,而不是直接修改 DOM。
总结
在 Vue 中,获取 DOM 节点的唯一标准方法是使用 ref
特性。步骤如下:
- 在目标元素上添加
ref="name"
。 - 在
mounted
钩子或之后的方法中,通过this.$refs.name
访问该 DOM 节点。
记住:ref
应作为最后的手段,在无法通过数据驱动解决时才使用。在 Vue 3 的组合式 API 中,则使用 ref()
函数配合 .value
来访问。
THE END