Vue3 ref 属性
ref 属性用于给元素或子组件注册引用信息,以便在 JavaScript 代码中直接访问 DOM 元素或组件实例。
基本说明
ref 是 Vue 中获取 DOM 元素或组件实例的重要方式。它允许我们在 Vue 实例挂载后直接操作 DOM 或调用子组件的方法。
- 类型: String | Function
- 作用: 访问 DOM 元素或子组件实例,进行焦点控制、方法调用等操作。
基本用法
1、Options API 中使用 ref
在 Options API 中,ref 注册的引用会存储在组件实例的 $refs 对象中:
实例
<template>
<div>
<input type="text" ref="inputField" />
<button @click="focusInput">聚焦输入框</button>
</div>
</template>
<script>
export default {
methods: {
focusInput() {
// 通过 $refs 访问 DOM 元素
this.$refs.inputField.focus()
}
}
}
</script>
<div>
<input type="text" ref="inputField" />
<button @click="focusInput">聚焦输入框</button>
</div>
</template>
<script>
export default {
methods: {
focusInput() {
// 通过 $refs 访问 DOM 元素
this.$refs.inputField.focus()
}
}
}
</script>
2、Composition API 中使用 ref
在 Composition API 中,推荐使用 useTemplateRef 来获取模板引用:
实例
<template>
<div>
<input type="text" ref="inputField" />
<button @click="focusInput">聚焦输入框</button>
</div>
</template>
<script setup>
import { useTemplateRef } from 'vue'
// 创建与模板中 ref 名匹配的引用
const inputField = useTemplateRef('inputField')
function focusInput() {
// 直接访问 DOM 元素
inputField.value?.focus()
}
</script>
<div>
<input type="text" ref="inputField" />
<button @click="focusInput">聚焦输入框</button>
</div>
</template>
<script setup>
import { useTemplateRef } from 'vue'
// 创建与模板中 ref 名匹配的引用
const inputField = useTemplateRef('inputField')
function focusInput() {
// 直接访问 DOM 元素
inputField.value?.focus()
}
</script>
使用场景
1、访问 DOM 元素
使用 ref 可以直接访问 DOM 元素,进行焦点控制、获取值等操作:
实例
<template>
<div>
<input type="text" ref="username" placeholder="用户名" />
<button @click="getValue">获取值</button>
</div>
</template>
<script>
export default {
methods: {
getValue() {
// 获取输入框的值
const value = this.$refs.username.value
console.log('输入的值:', value)
}
}
}
</script>
<div>
<input type="text" ref="username" placeholder="用户名" />
<button @click="getValue">获取值</button>
</div>
</template>
<script>
export default {
methods: {
getValue() {
// 获取输入框的值
const value = this.$refs.username.value
console.log('输入的值:', value)
}
}
}
</script>
2、访问子组件实例
使用 ref 可以访问子组件的实例,调用子组件的方法或访问其数据:
实例
<!-- 父组件 -->
<template>
<div>
<child-component ref="childRef"></child-component>
<button @click="callChildMethod">调用子组件方法</button>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
components: {
ChildComponent
},
methods: {
callChildMethod() {
// 调用子组件的方法
this.$refs.childRef.sayHello()
// 访问子组件的数据
console.log('子组件数据:', this.$refs.childRef.message)
}
}
}
</script>
<template>
<div>
<child-component ref="childRef"></child-component>
<button @click="callChildMethod">调用子组件方法</button>
</div>
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
components: {
ChildComponent
},
methods: {
callChildMethod() {
// 调用子组件的方法
this.$refs.childRef.sayHello()
// 访问子组件的数据
console.log('子组件数据:', this.$refs.childRef.message)
}
}
}
</script>
3、函数式 ref
ref 也可以接受一个函数,这个函数会在每次更新时被调用,可以完全控制引用的存储位置:
实例
<template>
<div>
<input type="text" :ref="el => inputEl = el" />
<button @click="focusInput">聚焦</button>
</div>
</template>
<script>
export default {
data() {
return {
inputEl: null
}
},
methods: {
focusInput() {
this.inputEl?.focus()
}
}
}
</script>
<div>
<input type="text" :ref="el => inputEl = el" />
<button @click="focusInput">聚焦</button>
</div>
</template>
<script>
export default {
data() {
return {
inputEl: null
}
},
methods: {
focusInput() {
this.inputEl?.focus()
}
}
}
</script>
注意事项
ref 注册时机:因为 ref 本身是由渲染函数的结果创建的,所以必须在组件挂载后才能访问它们。如果在
created生命周期钩子中访问,$refs还是空对象。
非响应式:
$refs是非响应式的,因此不应该在模板中将其用于数据绑定。只在 JavaScript 中使用它进行 DOM 操作。
避免滥用 ref:尽可能通过数据驱动和事件处理来操作 DOM 和子组件。过度使用 ref 会使代码难以维护。
实例
<!-- 不推荐:在 created 中访问 ref -->
<script>
export default {
created() {
console.log(this.$refs.inputField) // undefined
},
mounted() {
console.log(this.$refs.inputField) // 可以访问
}
}
</script>
<script>
export default {
created() {
console.log(this.$refs.inputField) // undefined
},
mounted() {
console.log(this.$refs.inputField) // 可以访问
}
}
</script>
与 v-for 配合
ref 也可以用于 v-for,会创建一个包含所有对应 DOM 元素或组件实例的数组:
实例
<template>
<div>
<div v-for="(item, index) in items" :key="item.id" :ref="el => setItemRef(el, index)">
{{ item.name }}
</div>
<button @click="logRefs">打印所有引用</button>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{ id: 1, name: '项目一' },
{ id: 2, name: '项目二' },
{ id: 3, name: '项目三' }
],
itemRefs: []
}
},
methods: {
setItemRef(el, index) {
if (el) {
this.itemRefs[index] = el
}
},
logRefs() {
console.log('所有引用:', this.itemRefs)
}
}
}
</script>
<div>
<div v-for="(item, index) in items" :key="item.id" :ref="el => setItemRef(el, index)">
{{ item.name }}
</div>
<button @click="logRefs">打印所有引用</button>
</div>
</template>
<script>
export default {
data() {
return {
items: [
{ id: 1, name: '项目一' },
{ id: 2, name: '项目二' },
{ id: 3, name: '项目三' }
],
itemRefs: []
}
},
methods: {
setItemRef(el, index) {
if (el) {
this.itemRefs[index] = el
}
},
logRefs() {
console.log('所有引用:', this.itemRefs)
}
}
}
</script>

Vue3 内置属性