Vue3中的常见组件通信之`$refs`、`$parent`

2024-06-09 11:52

本文主要是介绍Vue3中的常见组件通信之`$refs`、`$parent`,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Vue3中的常见组件通信之$refs$parent

概述

​ 在vue3中常见的组件通信有props、mitt、v-model、 r e f s 、 refs、 refsparent、provide、inject、pinia、slot等。不同的组件关系用不同的传递方式。常见的撘配形式如下表所示。

组件关系传递方式
父传子1. props
2. v-model
3. $refs
4. 默认插槽、具名插槽
子传父1. props
2. 自定义事件
3. v-model
4. $parent
5. 作用域插槽
祖传孙、孙传祖1. $attrs
2. provide、inject
兄弟间、任意组件间1. mitt
2. pinia

props和自定义事件详见:
Vue3中的常见组件通信之props和自定义事件
mitt用法详见:
Vue3中的常见组件通信之mitt
v-model用法详见:
Vue3中的常见组件通信之v-model
$attrs用法详见:
Vue3中的常见组件通信之$attrs

接下来是$refs$parent

6. r e f s 、 refs、 refsparent

$refs用于父传子,$parent用于子传父。

6.1准备组件

准备三个组件,一个父组件,两个子组件。

父组件代码:

<template><div class="Father"><div id="d1"><h3>这是父组件</h3>存款:{{ money }} 万元</div><Child1/><Child2/></div>	
</template><script setup lang="ts" name="Father">
import Child1 from './Child1.vue'
import Child2 from './Child2.vue'
import {ref} from 'vue'//数据
let money = ref(100)</script><style scoped>.Father{background-color: rgb(155, 162, 168);padding: 10px;margin: 10px;}#d1{margin-left: 10px;}
</style>

子组件1代码:

<template><div class="Child1"><h3>这是子组件1</h3><ul><li>书籍:{{ book }} 本</li><li>玩具:{{ toy }}</li></ul></div></template><script setup lang="ts" name="Child1">
import {ref} from 'vue'//数据
let book = ref(10)
let toy = ref('滑板车')</script><style scoped>.Child1{background-color: rgb(132, 114, 148);margin: 10px 0;padding: 10px;color: white;}
</style>

子组件2代码:

<template><div class="Child2"><h3>这是子组件2</h3><ul><li>书籍:{{ book }} 本</li><li>玩具:{{ toy }}</li></ul></div>	
</template><script setup lang="ts" name="Child2">
import {ref} from 'vue'//数据
let book = ref(6)
let toy = ref('水枪')</script><style scoped>.Child2{background-color: rgb(128, 132, 31);margin-top: 10px;padding: 10px;color:white}
</style>

运行效果如下:

image-20240607145314586

6.2$refs实现父传子通信

需要先了解标签的ref属性的基本知识,ref用在普通DOM标签上,获取的是DOM节点;ref用在组件标签上,获取的是组件实例对象。

了解上面的基础知识后,要在父组件中创建c1和c2,用来存储ref标记的内容:

//创建c1和c2,用于存储ref标记的内容
let c1 = ref()
let c2 = ref()

在CHild1和Ch2组件标签上添加ref属性:

<Child1 ref="c1"/>
<Child2 ref="c2"/>

在Child1和Child2的组件内需要添加以下代码,用来把数据交出去:

//把数据交出去
defineExpose({book,toy})

此时,在父组件中已经拿到了子组件中的数据,可以对这些数据进行操作,如下代码定义一个函数,用来改变子组件1中的toy的值:

function changeC1Toy(){c1.value.toy = '积木'
}

在父组件创建按钮,并绑定click事件,用来触发 changeC1Toy函数:

<button @click="changeC1Toy">修改子组件1中的玩具</button>

运行后效果如下:

$refs可以在父组件中获取所有的用ref标记的子组件的实例对象,如果没有用ref标记,则获取不到,例如再增加一个子组件Child3,代码如下:

<template><div class="Child3"><h3>这是子组件3</h3><ul><li>书籍:{{ book }} 本</li><li>玩具:{{ toy }}</li></ul></div></template><script setup lang="ts" name="Child3">
import {ref} from 'vue'//数据
let book = ref(30)
let toy = ref('毛绒玩具')//把数据交出去
defineExpose({book,toy})
</script><style scoped>.Child3{background-color: rgb(120, 148, 114);margin: 10px 0;padding: 10px;color: white;}
</style>

在父组件中引入子组件3:

import Child3 from './Child3.vue'

在页面呈现,但是不添加ref属性

<Child3 />

接下来给父组件创建一个按钮,并绑定click事件,触发changeAllBook()函数,并传入$refs

<button @click="changeAllBook($refs)">修改子组件的书籍数量</button>

changeAllBook的函数代码如下:

function changeAllBook(refs:any){console.log(refs)for (let key in refs){refs[key].book += 1}
}

运行后点击按钮,控制台打印的内容如下:

image-20240608161927543

可以看到$refs是一个响应式的对象,对象内是c1和c2,没有子组件3的实例对象。通过遍历把c1和c2中的book增加1,运行效果如下图:

以上通过操控父组件的按钮,实现改变子组件中书籍的数量,这便是父传子通信的一种。

6.3$parent实现子传父通信

$parent的用法与$refs用法类似,$parent获取的是父组件的实例对象,如下在子组件1中添加一个按钮,并绑定单击事件,触发minusMoney方法,实现减少父组件中的存款:

<button @click="minusMoney($parent)">减少父组件存款</button>

minusMoney的代码如下:

function minusMoney(parent:any){	parent.money -= 1
}

父组件需要写个宏函数把数据交出去:

//将数据交出去
defineExpose({money})

至此已经完成了子传父的通信,点击子组件中的按钮,可以对父组件中的数据进行操控,如下图:

6.4小结

以上便是$refs$parent实现父子间通信的用法,小结如下:

**$refs:**用来获取所有用ref标记的子组件的实例对象,得到的是响应式对象数据类型,不能获取没有用ref标记的子组件实例对象。

**$parent:**用来获取父组件的实例对象。

注意:组件中需要用宏函数defineExpose()把数据交出去,不然获取不到数据。

以下是完整代码:

父组件:

<template><div class="Father"><div id="d1"><h3>这是父组件</h3>存款:{{ money }} 万元</div><button @click="changeC1Toy">修改子组件1中的玩具</button><button @click="changeAllBook($refs)">修改子组件的书籍数量</button><!-- 组件标签的ref属性获取的是组件的实例对象 --><Child1 ref="c1"/><Child2 ref="c2"/><Child3 /></div>	
</template><script setup lang="ts" name="Father">
import Child1 from './Child1.vue'
import Child2 from './Child2.vue'
import Child3 from './Child3.vue'
import {ref} from 'vue'//数据
let money = ref(100)//创建c1和c2,用于存储ref标记的内容
let c1 = ref()
let c2 = ref()//方法
function changeC1Toy(){c1.value.toy = '积木'
}function changeAllBook(refs:any){// console.log(refs)for (let key in refs){refs[key].book += 1}
}//将数据交出去
defineExpose({money})
</script><style scoped>.Father{background-color: rgb(155, 162, 168);padding: 10px;margin: 10px;}#d1{margin-left: 10px;}
</style>

子组件1

<template><div class="Child1"><h3>这是子组件1</h3><ul><li>书籍:{{ book }} 本</li><li>玩具:{{ toy }}</li></ul><button @click="minusMoney($parent)">减少父组件存款</button></div>
</template><script setup lang="ts" name="Child1">
import {ref} from 'vue'//数据
let book = ref(10)
let toy = ref('滑板车')//方法
function minusMoney(parent:any){	parent.money -= 1
}//把数据交出去
defineExpose({book,toy})
</script><style scoped>.Child1{background-color: rgb(132, 114, 148);margin: 10px 0;padding: 10px;color: white;}button{color: #000;}
</style>

子组件2

<template><div class="Child2"><h3>这是子组件2</h3><ul><li>书籍:{{ book }} 本</li><li>玩具:{{ toy }}</li></ul></div>	
</template><script setup lang="ts" name="Child2">
import {ref} from 'vue'//数据
let book = ref(6)
let toy = ref('水枪')//把数据交出去
defineExpose({book,toy})
</script><style scoped>.Child2{background-color: rgb(128, 132, 31);margin-top: 10px;padding: 10px;color:white}
</style>

这篇关于Vue3中的常见组件通信之`$refs`、`$parent`的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1045107

相关文章

Java实现Excel与HTML互转

《Java实现Excel与HTML互转》Excel是一种电子表格格式,而HTM则是一种用于创建网页的标记语言,虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,下面我们就来看看... Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两

Spring常见错误之Web嵌套对象校验失效解决办法

《Spring常见错误之Web嵌套对象校验失效解决办法》:本文主要介绍Spring常见错误之Web嵌套对象校验失效解决的相关资料,通过在Phone对象上添加@Valid注解,问题得以解决,需要的朋... 目录问题复现案例解析问题修正总结  问题复现当开发一个学籍管理系统时,我们会提供了一个 API 接口去

vue解决子组件样式覆盖问题scoped deep

《vue解决子组件样式覆盖问题scopeddeep》文章主要介绍了在Vue项目中处理全局样式和局部样式的方法,包括使用scoped属性和深度选择器(/deep/)来覆盖子组件的样式,作者建议所有组件... 目录前言scoped分析deep分析使用总结所有组件必须加scoped父组件覆盖子组件使用deep前言

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

基于Qt Qml实现时间轴组件

《基于QtQml实现时间轴组件》时间轴组件是现代用户界面中常见的元素,用于按时间顺序展示事件,本文主要为大家详细介绍了如何使用Qml实现一个简单的时间轴组件,需要的可以参考下... 目录写在前面效果图组件概述实现细节1. 组件结构2. 属性定义3. 数据模型4. 事件项的添加和排序5. 事件项的渲染如何使用

React实现原生APP切换效果

《React实现原生APP切换效果》最近需要使用Hybrid的方式开发一个APP,交互和原生APP相似并且需要IM通信,本文给大家介绍了使用React实现原生APP切换效果,文中通过代码示例讲解的非常... 目录背景需求概览技术栈实现步骤根据 react-router-dom 文档配置好路由添加过渡动画使用

C语言线程池的常见实现方式详解

《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初

使用Vue.js报错:ReferenceError: “Vue is not defined“ 的原因与解决方案

《使用Vue.js报错:ReferenceError:“Vueisnotdefined“的原因与解决方案》在前端开发中,ReferenceError:Vueisnotdefined是一个常见... 目录一、错误描述二、错误成因分析三、解决方案1. 检查 vue.js 的引入方式2. 验证 npm 安装3.

vue如何监听对象或者数组某个属性的变化详解

《vue如何监听对象或者数组某个属性的变化详解》这篇文章主要给大家介绍了关于vue如何监听对象或者数组某个属性的变化,在Vue.js中可以通过watch监听属性变化并动态修改其他属性的值,watch通... 目录前言用watch监听深度监听使用计算属性watch和计算属性的区别在vue 3中使用watchE

python解析HTML并提取span标签中的文本

《python解析HTML并提取span标签中的文本》在网页开发和数据抓取过程中,我们经常需要从HTML页面中提取信息,尤其是span元素中的文本,span标签是一个行内元素,通常用于包装一小段文本或... 目录一、安装相关依赖二、html 页面结构三、使用 BeautifulSoup javascript