【Vue3】组件通信之$refs
- 背景
- 简介
- 开发环境
- 开发步骤及源码
- 总结
背景
随着年龄的增长,很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来,技术出身的人总是很难放下一些执念,遂将这些知识整理成文,以纪念曾经努力学习奋斗的日子。本文内容并非完全原创,大多是参考其他文章资料整理所得,感谢每位技术人的开源精神。
简介
本文介绍 Vue3 中如何使用 $refs
实现父组件向子组件传数据。
Vue3 中组件间通信包括:
- 父组件向子组件传数据,实现方案有:
props
v-model
$refs
- 默认插槽 / 具名插槽
- 子组件向父组件传数据
props
v-model
$parent
- 自定义事件
- 作用域插槽
- 父组件与子组件的子组件互传数据,即与孙子组件互传数据
$attrs
provider
&inject
- 任意组件间传数据
mitt
Pinia
开发环境
分类 | 名称 | 版本 |
---|---|---|
操作系统 | Windows | Windows 11 |
IDE | Visual Studio Code | 1.91.1 |
开发步骤及源码
1> 创建 Vue3 工程,参考:【Vue3】工程创建及目录说明。
2> 删除 src
目录下 assets
和 components
目录。
3> 修改 src
目录下 main.ts
。
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
4> 定义子组件。
<template>
<div class="content">
<h2>{{ name }}</h2>
<div class="book" v-for="book in books" :key="book.id">
<h3>书名:{{ book.title }}</h3>
<h3>作者:{{ book.author }}</h3>
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, ref } from 'vue';
const name = ref('历史书屋')
const books = reactive([
{ id: '001', title: '长安的离职', author: '马伯庸'},
{ id: '001', title: '坐天下', author: '张宏杰'},
{ id: '001', title: '饥饿的盛世', author: '张宏杰'},
{ id: '001', title: '风起陇西', author: '马伯庸'},
])
// 将数据权限交给父组件
defineExpose({ name, books })
</script>
<style scoped lang="scss">
.content {
background-color: greenyellow;
padding: 20px;
.book {
background-color: white;
border: 1px solid blue;
margin-bottom: 10px;
padding: 0 10px;
width: 300px;
}
}
</style>
数据定义在子组件,且使用 defineExpose
函数将数据权限交给父组件。
注意:需要执行 npm install -D sass
命令安装 CSS 预处理器。
5> 修改 Vue 根组件 src/App.vue
,使用组件标签的 ref
属性向子组件传数据。
<template>
<div class="parent">
<button @click="changeName">变更书店名称</button>
<button @click="removeBook">下架书籍</button>
<BookStore ref="bookStore" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import BookStore from './components/BookStore.vue'
const bookStore = ref()
function changeName() {
bookStore.value.name = '文化书屋'
}
function removeBook() {
bookStore.value.books.shift()
}
</script>
<style scoped lang="scss">
.parent {
background-color: orange;
padding: 20px;
button {
font-size: 18px;
font-weight: bold;
height: 40px;
margin-bottom: 10px;
margin-right: 10px;
width: 150px;
}
}
</style>
6> 执行命令 npm run dev
启动应用,浏览器访问:http://localhost:5173/
。
- 点击
变更书店名称
按钮,子组件中的历史书屋
变成文化书屋
; - 点击
下架书籍
按钮,子组件的书籍列表会从第一项开始逐一删除。
7> 以上代码使用组件标签的 ref
属性实现父组件向子组件传数据,如果父组件中存在多个子组件并需要同时向这些子组件传数据,则按此方法需要使用多次组件标签 ref
,且要定义多个 ref
变量引用。这种情况可以使用 $refs
优化,修改 App.vue
。
<template>
<div class="parent">
<button @click="changeName($refs)">变更书店名称</button>
<button @click="removeBook($refs)">下架书籍</button>
<BookStore ref="bookStore" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import BookStore from './components/BookStore.vue'
function changeName(refs: {[key: string]: any}) {
for (let key in refs) {
refs[key].name = '文化书屋'
}
}
function removeBook(refs: any) {
for (let key in refs) {
refs[key].books.shift()
}
}
</script>
<style scoped lang="scss">
.parent {
background-color: orange;
padding: 20px;
button {
font-size: 18px;
font-weight: bold;
height: 40px;
margin-bottom: 10px;
margin-right: 10px;
width: 150px;
}
}
</style>
可见并未在 <script>
中定义 ref
引用,通过 $refs
可以获取到所有 ref
引用。需要注意的是两个方法中的函数参数声明:refs: {[key: string]: any}
和 refs: any
,都是为了解决 TypeScript 检查错误,这两种写法可任选其一。
总结
$refs
的使用场景是:父组件向多个子组件同时传数据,本质还是组件标签的ref
属性;- 子组件需要使用
defineExpose
函数将数据权限交给父组件,此函数参数为一个对象,由暴露的数据组成。