也是零零散散用 vue3 来搞一些前端的页面, 每次在组件通信, 主要是传数据这块总是忘记, 大多无非父传子, 子传父等情况, 这里再来做一个小结.

父传子 Props

最常见的就是父组件给子组件传递数据, 不论是传字符串也好, 还是数组, 对象, 函数等, 都可以通过 属性传值 的方式, 子组件通过 defineProps 对应接收即可.

App.vue

<script setup>
import Son from './components/Son.vue' // 1. 定义父组件要通过 arr 属性传递给子组件 Son.vue 的数据
const arr = [1, 2, { name: 'youge', age: 18 }]
</script> <template>
<!-- 子组件 -->
<Son :arr="arr" @refresh="handleRefresh"></Son>
</template>

Child.vue

<script setup>
import { ref } from 'vue' defineProps({
arr: Array,
}) </script> <template>
<div>
子组件:
<br /> <br />
父组件传来的数据: <br />
{{ arr }}
</div>
</template>
子组件:

父组件传来的数据:
[ 1, 2, { "name": "youge", "age": 18 } ]

总之父传子, 通过属性传递方式, 啥都能传哈, 子组件通过defineProps 都能接收处理.

父传孙 provide / inject

常规父子组件通信的流程是通过 props 父 -> 子 -> 孙 -> 曾孙 ... 这样逐级传递.

但通过 provide -> inject 这种依赖注入的方式, 可以一步透传数据, 不论嵌套多深, 有点厉害.

App.vue

通过 provide(key, value) 开始向任何后台派发数据啦.

<script setup>
import { ref, provide } from 'vue'
import Son from './components/Son.vue' // 要传递给孙组件的数据
const data = [
{ name: 'youge', age: 20 },
{ name: 'yaya', age: 18 }
] // 直接穿透中间层, 哪里想引用直接进行 inject
provide('data', data) </script> <template>
<div class="con">
父组件
</div> <!-- 调用子组件 -->
<Son /> </template> <style scoped>
.con {
margin: 100px;
width: 300px;
height: 200px;
border: solid 1px red;
}
</style>

Son.vue

对于祖父辈的 provide(key, value) 中间商也是可以通过 inject(key) 获取到数据, 当然后面的也可享受恩泽.

<template>
<div class="con">
<p>子组件:</p>
{{ data }}
</div>
<!-- 调用子组件, 父组件的孙组件 -->
<GrandSon />
</template> <script setup>
import GrandSon from './grandson.vue'
import { inject } from "vue" const data = inject('data') </script> <style scoped>
.con {
margin: 100px;
width: 300px;
height: 200px;
border: solid 1px blue;
}
</style>

GrandSon.vue

通过 inject(key) 来接收

<script setup>
import { inject } from 'vue' // 接收曾祖父传递过来的数据
const data = inject('data') </script> <template>
<div class="con">
<p>我是孙组件, 接收爷组件传递过来的数据: </p>
{{ data }}
</div>
</template> <style scoped>
.con {
margin: 100px;
height: 200px;
width: 500px;
border: 1px solid green;
}
</style>

子传父 Emit

而使用最多的场景是将页面拆分为很多小组件, 子组件, 数据在子组件交互然后渲染或者传递给父组件, 这种情况就用 $emit 来实现.

先又子组件派发, 传递, 然后父组件对应接收.

Child.vue

<script setup>
const data = [
{ name: 'huoya', age: 18 },
{ name: 'cj' , age: 20 }
] // 01: 都是要进行先定义出事件名称
const emit = defineEmits(['refresh_01', 'refresh_02']) // 02: 推荐函数写法可以更灵活控制 emit 的触发时间
const handleClick = () => {
emit('refresh_02', data)
} </script> <template>
<div class="con">
<!-- 行内写法 -->
<button @click="$emit('refresh_01', data)">标签写法: 向父组件传数据</button>
<!-- 函数写法 -->
<button @click="handleClick">函数写法: 向父组件传数据</button>
</div>
</template>

App.vue

<script setup>
import { ref } from 'vue'
import Son from './components/Son.vue' const sonData_01 = ref(null)
const sonData_02 = ref(null) // 处理子组件传递过来的数据
const handleRefresh_01 = (e) => {
sonData_01.value = e
} const handleRefresh_02 = (e) => {
sonData_02.value = e
}
</script> <template>
<div class="con">
父组件:
<br /><br>
{{ sonData_01 }} <br /><br>
{{ sonData_02 }}
</div> <!-- 调用子组件 -->
<Son @refresh_01="handleRefresh_01" /> <Son @refresh_02="handleRefresh_02" /> </template>

小结子传父通过 emit 事件实现的 4 步走:

  • 01: 在子组件先定义事件, const emit = defineEmits(['A', 'B'])
  • 02: 在子组件调用事件, 向父组件传递数据 const handleClick = () => { emit('A', data }
  • 03: 在父组件通过 @A="handleA" 来监听子组件传过来的事件 A
  • 04: 在父组件定义一个方法 handleA 来接收子组件通过 事件A 传递过来的数据

子传父 DefineExpos / Ref

还有种常用的方法是, 子组件通过 defineExpose 向外暴露一个方法,

然后父组件通过 ref 调用子组件的方法, 顺带将数据带过来.

Child.vue

  • defineExpose 暴露
<script setup>
import { ref, reactive } from 'vue' // 模拟接口数据
const data = reactive([
{ name: 'huoya', age: 18 },
{ name: 'cj' , age: 20 }
]
) function getData (syncData) {
data.value = syncData
return data
} // 将获取数据的方法向外暴露
defineExpose({
getData
}) </script>

App.vue

  • ref 绑定
<script setup>
import { ref, nextTick } from 'vue'
import Son from './components/Son.vue' const sonRef = ref(null)
const sonData = ref(null) // nextTick(() => {
// sonData.value = sonRef.value.getData()
// }) const getData = () => sonData.value = sonRef.value.getData() </script> <template>
<!-- 父组件 -->
<div class="con">
父组件:
<br /><br>
<p>子组件数据: </p> <br>
{{ sonData }}
</div> <!-- 调用子组件 -->
<div>
<button @click="getData">获取子组件数据</button>
<Son ref="sonRef" />
</div> </template>

双向绑定 v-model

v-model 可以在组件上使用以实现双向绑定, 自然也是包含子传父的场景啦.

从 Vue 3.4 开始,推荐的实现方式是使用 defineModel()宏:

Child.vue

定义 defineModel

<script setup>
import { reactive } from 'vue' // 模拟接口数据
const data = reactive([
{ name: 'huoya', age: 18 },
{ name: 'cj', age: 20 }
]
)
// 通过 defineModel() 返回的是一个 ref
const modelData = defineModel() function getData() {
modelData.value = data
} </script> <template>
<div class="con">
<p>子组件</p>
<button @click="getData">向父组件传数据</button>
</div>
</template> <style scoped>
.con {
margin: 100px;
width: 300px;
height: 200px;
border: solid 1px blue;
}
</style>

App.vue

绑定 v-model

<script setup>
import { ref } from 'vue'
import Son from './components/Son.vue' const sonData = ref(null) </script> <template>
<div class="con">
父组件:
<br /><br>
<p>子组件数据: </p> <br>
{{ sonData }}
</div> <!-- 调用子组件 -->
<div>
<Son v-model="sonData" />
</div> </template> <style scoped>
.con {
margin: 100px;
width: 300px;
height: 200px;
border: solid 1px red;
}
</style>

defineModel() 返回的值是一个 ref。它可以像其他 ref 一样被访问以及修改,不过它能起到在父组件和当前变量之间的双向绑定的作用:

  • 它的 .value 和父组件的 v-model 的值同步;
  • 当它被子组件变更了,会触发父组件绑定的值一起更新

它的底层机制是:

  • 一个名为 modelValue 的属性, 本地 ref 的值与其同步
  • 一个名为 update:modelValue 的事件, 当本地 ref 的值发生变化时触发

在用 vue 3.4 之前的版本, 通常需要自己手动来完成方法和事件的编写.

Child.vue

手动定义 defineProps()defineEmits()

<template>
<div class="con">
<p>子组件</p>
<button @click="getData">向父组件传数据</button>
</div>
</template> <script setup> // 1. 属性值必须要是 modelValue
const props = defineProps({
modelValue: [String, Array]
}) // 2. 事件名称必须是 update:modelvalue
const emit = defineEmits(['update:modelValue']) // 模拟接口数据
const data = [
{ name: 'huoya', age: 18 },
{ name: 'cj', age: 20 }
] const getData = () => {
emit("update:modelValue", data)
} </script> <style scoped>
.con {
margin: 100px;
width: 300px;
height: 200px;
border: solid 1px blue;
}
</style> -->

App.vue

<script setup>
import { ref, nextTick } from 'vue'
import Son from './components/Son.vue' const sonData = ref(null) </script> <template>
<!-- 父组件 -->
<div class="con">
父组件:
<br /><br>
<p>子组件数据: </p> <br>
{{ sonData }}
</div> <!-- 调用子组件 -->
<div>
<Son v-model="sonData" />
</div> </template> <style scoped>
.con {
margin: 100px;
width: 300px;
height: 200px;
border: solid 1px red;
}
</style>

常用的这几个方式就基本足够用了.

Vue3 组件通信方式小结的更多相关文章

  1. 盘点Vue2和Vue3的10种组件通信方式(值得收藏)

    Vue中组件通信方式有很多,其中Vue2和Vue3实现起来也会有很多差异:本文将通过选项式API 组合式API以及setup三种不同实现方式全面介绍Vue2和Vue3的组件通信方式.其中将要实现的通信 ...

  2. 整理4种Vue组件通信方式

    整理4种Vue组件通信方式 重点是梳理了前两个,父子组件通信和eventBus通信,我觉得Vue文档里的说明还是有一些简易,我自己第一遍是没看明白. 父子组件的通信 非父子组件的eventBus通信 ...

  3. Angular2 父子组件通信方式

    https://www.jb51.net/article/133868.htm 这次给大家带来Angular2 父子组件通信方式,使用Angular2 父子组件通信方式的注意事项有哪些,下面就是实战案 ...

  4. Vue组件通信方式全面详解

    vue组件通信方式全面详解 众所周知,Vue主要思想就是组件化开发.因为,在实际的项目开发中,肯定会以组件的开发模式进行.形如页面和页面之间需要通信一样,Vue 组件和组件之间肯定也需要互通有无.共享 ...

  5. Vue中的8种组件通信方式

    Vue是数据驱动视图更新的框架,所以对于vue来说组件间的数据通信非常重要. 常见使用场景可以分为三类: 父子组件通信: props / $emit $parent / $children provi ...

  6. Vite+TS带你搭建一个属于自己的Vue3组件库

    theme: nico 前言 随着前端技术的发展,业界涌现出了许多的UI组件库.例如我们熟知的ElementUI,Vant,AntDesign等等.但是作为一个前端开发者,你知道一个UI组件库是如何被 ...

  7. 从0搭建Vue3组件库:button组件

    button组件几乎是每个组件库都有的:其实实现一个button组件是很简单的.本篇文章将带你一步一步的实现一个button组件.如果你想了解完整的组件库搭建,你可以先看使用Vite和TypeScri ...

  8. 从0搭建vue3组件库:Shake抖动组件

    先看下效果 其实就是个抖动效果组件,实现起来也非常简单.之所以做这样一个组件是为了后面写Form表单的时候会用到它做一个规则校验,比如下面一个简单的登录页面,当点击登录会提示用户哪个信息没输入,当然这 ...

  9. 从0搭建vue3组件库: 如何完整搭建一个前端脚手架?

    相信大家在前端开发中都使用过很多前端脚手架,如vue-cli,create-vite,create-vue等:本篇文章将会为大家详细介绍这些前端脚手架是如何实现的,并且从零实现一个create-kit ...

  10. 从0搭建vue3组件库:自动化发布、管理版本号、生成 changelog、tag

    今天看到一篇文章中提到了一个好用的工具release-it.刚好可以用在我正在开发的vue3组件库.纸上得来终觉浅,绝知此事要躬行,说干就干,下面就介绍如何将release-it应用到实际项目中,让组 ...

随机推荐

  1. Ollama模型迁移

    技术背景 在前面的一些文章中,我们介绍过使用Ollama在Linux平台加载DeepSeek蒸馏模型,使用Ollama在Windows平台部署DeepSeek本地模型.除了使用Ollama与模型文件交 ...

  2. 工业机器人维修保养|ABB机器人IRB 6700维修保养技巧

    通过机器人维修保养服务定制合理的维修保养工作,可以确保ABB机器人IRB 6700的持续稳定运行,延长其使用寿命,为企业的生产提供有力保障. 一.ABB机器人IRB 6700日常检查与维护 外观检查: ...

  3. C#使用Interlocked实现线程同步

    通过System.Threading命名空间的Interlocked类控制计数器,从而实现进程 的同步.Iterlocked类的部分方法如下表: 示例,同时开启两个线程,一个写入数据,一个读出数据 代 ...

  4. C# 多线程编程及其几种方式

    引言: 进程(process):应用程序的实例要使用的资源的集合.每个进程被赋予了一个虚拟地址空间,确保在一个进程中使用的代码和数据无法由另一个进程访问. 线程(thread):程序中的一个执行流,每 ...

  5. RTC、直播、点播技术对比|腾讯云/即构/声网如何 选型 2025 版

    前言 作为一个有多年实战经验的开发者,在音视频技术领域我深刻体会到 RTC(实时通信).直播和点播三者的不同.虽然它们的核心都涉及音视频内容的传输,但在实际应用中,它们的技术实现.使用场景以及所面临的 ...

  6. Ubuntu下如何管理多个ssh密钥

    Ubuntu下如何管理多个ssh密钥 前言 ‍ 我一直在逃避这个问题,误以为我能够单纯地用一个 ssh 走天下. 好吧,现实是我不得不管理多个 ssh 做,那就写个博客总结一下吧. 查阅后发现前人已经 ...

  7. Linux 防火墙及开放端口管理

    查看防火墙是否开启systemctl status firewalld 若没有开启则是开启状态systemctl start firewalld  关闭则start改为stop 查看所有开启的端口fi ...

  8. Flask应用实战经验总结:使用工厂函数创建app与uWSGI服务部署启动失败解决方案

    在 Flask 应用开发中,使用工厂函数创建应用实例,并借助 uWSGI 服务进行部署,是常见且高效的组合. 然而,在实际操作过程中,uWSGI 配置文件与应用启动函数之间的关系复杂,容易引发各种问题 ...

  9. NumPy学习10

    今天学习了3节: 18, NumPy副本和视图 19, NumPy字节交换 20, NumPy Matrix矩阵库 numpy_test10.py : import numpy as np ''' 1 ...

  10. 为什么AI教师难以实现

    提供AI应用咨询+陪跑服务,有需要回复1 本周为一家教育公司提供了全天的AI的培训,后续涉及AI+教育领域的项目开发,而我去年就做过AI教师项目,所以对AI+教育有一定熟悉度. 下来后又拜访了一家互联 ...