虽然vuejs的极大程度的减少了对dom的操作,定义了prop 和事件,但有时你可能仍然需要直接访问 JavaScript 中的子组件。此时可使用ref为子组件或 HTML 元素指定引用 ID。接下来通过几个简单的示例,演示如果使用vue3.2的script setup语法糖进行模板引用。
一、ref简单使用
获取模板内button元素,并在控制台打印。
1. 示例代码
<template>
<button ref="button">这是一个按钮</button>
</template>
<script setup>
import {ref, onMounted} from 'vue'
const button = ref(null)
onMounted(() => {
// DOM元素将在初始渲染后分配给ref
console.log(button.value)
})
</script>
<style scoped lang="scss">
</style>
2. 执行结果

二、父组件获取子组件变量
1. 父组件(Test.vue)
<template>
<div>
<Demo ref="child"></Demo>
<br/>
父组件获取到子组件数据——>{{ childValue }}
<br/>
<button @click="getChildValue">获取子组件数据</button>
</div>
</template>
<script setup>
import {ref} from "vue";
import Demo from "@/components/Demo.vue";
const child = ref(null);
const childValue = ref()
const getChildValue = () => {
childValue.value = child.value.count
};
</script>
<style scoped>
</style>
2. 子组件(Demo.vue)
<template>
<div>子组件计数:{{ count }}</div>
</template>
<script setup>
import {ref} from "vue";
const count = ref(10);
defineExpose({
count
})
</script>
<style scoped>
</style>
3. 执行结果

4. 注意事项
- 因为是调用组件的变量和方法。因此要给组件添加ref,而不是外层的html标签。
- 使用 <script setup> 的组件,默认不会暴露。为了在 <script setup> 组件中使用要暴露出去的属性,需要使用 defineExpose声明。
三、父组件执行子组件方法
1. 父组件(Test.vue)
<template>
<div>
<Demo ref="child"></Demo>
<br/>
父组件获取到子组件数据——>{{ childValue }}
<br/>
<button @click="getChildValue">父组件获取子组件数据</button>
<br/>
<button @click="childValueAdd">父组件执行子组件事件</button>
</div>
</template>
<script setup>
import {ref} from "vue";
import Demo from "@/components/Demo.vue";
const child = ref(null);
const childValue = ref()
const getChildValue = () => {
childValue.value = child.value.count
};
const childValueAdd = () => {
child.value.add()
}
</script>
<style scoped>
</style>
2. 子组件(Demo.vue)
<template>
<div>子组件计数:{{ count }}</div>
<br/>
<button @click="add">子组件事件:值+1</button>
</template>
<script setup>
import {ref} from "vue";
const count = ref(10);
const add = () => {
count.value++
}
defineExpose({
count,
add
})
</script>
<style scoped>
</style>
3. 执行结果

四、组件ref与标签ref区别
1. 组件ref
<template>
<div>
<Demo ref="child"></Demo>
</div>
</template>
<script setup>
import {onMounted, ref} from "vue";
import Demo from "@/components/Demo.vue";
const child = ref(null);
onMounted(() => {
console.log(child.value)
})
</script>
<style scoped>
</style>

- 通过打印结果可知,获取到的结果是组件的变量和方法
2. 标签ref
<template>
<div ref="child">
<Demo></Demo>
</div>
</template>
<script setup>
import {onMounted, ref} from "vue";
import Demo from "@/components/Demo.vue";
const child = ref(null);
onMounted(() => {
console.log(child.value)
})
</script>
<style scoped>
</style>

- 通过打印结果可知,获取到的结果是html元素
3. 总结
对比可知,组件添加ref后,打印的是组件的变量和方法;组件外层元素添加ref后,打印的是html节点。 因此,当调用组件的变量和方法时,需要在组件上添加ref;当对组件的dom元素进行操作时,应该在组件外层嵌套标签,并添加ref。
参考链接
- vue ref模板引用
- vue3.2 defineexpose
https://vue-docs-next-zh-cn.netlify.app/api/sfc-script-setup.html#defineexpose