对于日常使用vue3开发项目的前端小伙伴来说,组件通信方式可以说是必会的基本功,今天带大家一起盘下vue3的通信方式。

我们这里按照组件的关系来划分。总共包含14中组件通信方式

  • 一、父子通信
  1. props
  2. defineEmits
  3. $attrs
  4. $ref + defineExpose
  5. $parent
  6. 作用域插槽
  7. v-model
  • 二、兄弟组件通信
  1. mitt
  2. $parent
  3. vuex/pinia
  4. app.config.globalProperties
  • 三、跨层级通信
  1. mitt
  2. vuex/pinia
  3. provide/inject
  • 四:其它方式
    • 浏览器本地存储storage
    • 全局window对象
    • ES6模块化import/export

一:父子通信

1.1、父传子:props

最最常用的通信方式是props了,父组件通过props方式将属性传递给子组件,子组件接受props并用于数据操作和页面渲染。

注意:子组件不要直接修改父组件传递过来的props,保持自上而下单项数据流,这样会让数据的流向十分清晰,方便后续维护!

// Parent.vue
<template>
<Child :msg="msg"/>
</template> <script setup>
import { ref } from 'vue';
import Child from './components/Child.vue'; const msg = ref('hello world');
</script> // Child.vue
<template>
<div>
propsData:{{ msg }}
</div>
</template> <script setup>
defineProps({
msg: String
})
</script>

1.2、子传父:defineEmits

通过defineEmits可以让子组件的值传递到父组件中。

其用法如下:

  1. 先在子组件中用defineEmits([...emitName])定义一个或多个emit,它的返回值是一个emits函数,然后可以通过调用emits函数向父组件发射时间,并携带参数。
// Child.vue
<template>
<div @click="onClick">
child
</div>
</template> <script setup>
const emits = defineEmits(['update']);
const onClick = () => {
emits('update', 'child update');
}
</script>
  1. 在父组件中通过@符 + 事件名监听子组件发射出来的事件,并接收其传过来的值。
// Parent.vue
<template>
<div>
Parent
<Child @update="update"/>
</div>
</template> <script setup>
import Child from './Child.vue';
const update = val => {
console.log(val); // 当子组件点击事件触发后,这里会打印 child update
}
</script>

vue2的组件中还可以通过this.$onthis.$emit监听发射事件,以达到传值的目的,但在vue3已废弃这种写法。

1.3、$attrs

如果需要在子组件中接收的props很多,如果在props声明比较繁琐,所以vue给我们提供了一个优雅的解决方案,即$attrs$attrs指的是父组件传递给子组件的所有属性中,剔除在props中定义的那部分之后,剩下的就会放在$attrs中。

举个例子:

// Parent.vue
<template>
<div>
Parent
<Child :msg1="1" :msg2="2" />
</div>
</template>

这里父组件给子组件传递了两个属性msg1msg2

// Child.vue
<template>
<div>
child: {{ $attrs }}
</div>
</template> <script setup>
defineProps({
msg1: String
})
</script>

这里子组件使用了defineProps定义了msg1,则页面中$attrs的值为{ msg2: 2 }

还可以使用v-bind$attrs的所有数据,以属性的方式全部传递到子组件中,我们平常在封装组件的时候,这个东西就能帮助我们实现组件的属性透传,十分好用。

<template>
<Child v-bind="$attrs"/>
</template>

注意:在vue3中$listeners已废弃,无法使用。

1.4、$ref + defineExpose

通过$ref可以拿到组件的实例,defineExpose可以显式指定在 <script setup> 组件中要暴露出去的属性,它两一起配合使用,就能实现父子组件的通信。

其用法如下:

  1. 在子组件中通过defineExpose暴露一个update方法。
// Child.vue
<script setup>
defineExpose({
update(val) {
console.log('父组件传递过来的值', val);
}
})
</script>
  1. 在父组件中通过ref拿到组件实例并调用子组件暴露的update方法。
// Parent.vue
<template>
<div>
Parent
<Child ref="childRef"/>
</div>
</template> <script setup>
import Child from './Child.vue';
import { ref, onMounted } from 'vue'; const childRef = ref(null); onMounted(() => {
childRef.value.update('hello')
})
const update = () => {} </script>

1.5、$parent

$parent代表当前组件的父组件实例,如果当前组件是顶层组件,则$parent的值为null

我们可以通过$parent拿到父组件的实例,自然就可以进行父子组件的交互了。一般也是和defineExpose配合使用,和$ref + defineExpose用法类似,这里就不多说了。

注意:$children在vue3中已经废弃,无法使用。

1.6、作用域插槽

通过作用域插槽可以实现子组件向父组件传递数据。

子组件代码:

<template>
<div>
<slot :data="{ a:1, b: 2 }"/>
</div>
</template>

子组件可以在slot标签上传递数据给父组件。

父组件代码:

<template>
<Child>
<template v-slot="slotProps">
{{ slotProps.data }}
</template>
</Child>
</template>
<script setup>
import Child from './Child.vue';
</script>

父组件用v-slot来接收数据,并渲染到页面上。

1.7、v-model

v-model可以在组件上使用以实现双向绑定,vue内部会帮你传递值和绑定事件,也是达到了父子组件通讯的效果。

vue3.4开始,还可以使用defineModel便利宏,其用法如下:

子组件代码:

// Child.vue
<template>
<div>model的值: {{ model }}</div>
<button @click="handleClick">+1</button>
</template> <script setup>
const model = defineModel() function handleClick() {
model.value++
}
</script>

父组件代码:

// Parent.vue
<template>
<Child1 v-model="modelValue"></Child1>
Parent:{{ modelValue }}
</template> <script setup>
import Child from './Child.vue';
const modelValue = ref(0)
</script>

defineModel的返回值就是一个ref,你可以随意访问和修改它,并且它会和父组件的v-model绑定的值保持同步,也就是实现了双向绑定

二、兄弟组件

两个兄弟关系组件进行通信,我们一般会借助第三方媒介

2.1、mitt

mitt相当于我们vue2的事件总线$bus,只是vue3将其废弃,所以我们借助mitt实现类似$bus的效果。

用法如下:

  1. 安装mitt
npm install mitt
  1. 初始化mitt
// emitter.js
import mitt from'mitt';
export default mitt();

兄弟组件1:

<script setup>
import emitter from '@/utils/emitter'
emitter.on('update', (val) => {
console.log('update事件触发', val)
})
</script>

兄弟组件2:

<script setup>
import emitter from '@/utils/emitter' setTimeout(() => {
emitter.emit('update', 'hello')
}, 1000)
</script>

2.2、$parent

我们可以把状态(即数据)定义在父组件中,两个兄弟组件可以借助其共同的父组件共享同一份数据,间接实现通信。

2.3、vuex/pinia

vuexvue官方提供的状态管理工具,用它可以实现全局的状态共享,自然也可以实现兄弟组件的通信了。当然也可以使用pinia替代vuex

2.4、app.config.globalProperties

app.config.globalProperties是一个全局的对象,在应用内所有组件实例都能访问到,当组件属性名和它发生同名冲突时,采取就近原则,以组件的为准,这个就相当于vue2Vue.prototype

三、跨层级通信

3.1、mitt

mitt可以实现全局的通信,这个在上面介绍兄弟组件通信的时候已经说过,这里不再多说了。

3.2、vuex/pinia

vuexpinia都是全局的状态管理工具,跨层级通信也不再话下。

3.3、provide/inject

provide/injectvue3提供的可以跨层级通信的方式。

其用法如下:

  1. 父组件/根组件中定义provide,提供数据。
// App.vue
<script setup>
import { ref, provide } from 'vue'; const name = ref('sam');
provide('name', name)
</script>
  1. 子组件/孙子组件中使用inject,注入数据。
// 后代组件
<script setup>
import { inject } from 'vue'; const name = inject('name');
console.log('name', name.value); // 输出name
</script>

四、其它方式

4.1、浏览器本地存储storage

html5提供了一套storage API,包括了localStoragesessionStorage,它实现持久化存储、缓存等功能,自然也可以用来组件间通信了。

// 组件A
<script setup>
sessionStorage.setItem('name', 'jack');
</script> // 组件B
<script setup>
setTimeout(() => {
console.log(sessionStorage.getItem('name')); //打印 jack
}, 1000)
</script>

这里我在组件A使用sessionStarge设置了一个name值,在组件B里面就能拿到了,只要保证获取值在设置值之后执行就行了。

4.2、全局window对象(不推荐使用)

window作为一个全局对象,当然也可以使用它来通信了,不过它既然谁都可以访问到,就存在如下问题:

  1. 命令冲突问题
  2. 难以追踪数据修改,可维护性差;
  3. 挂在window上的数据难以销毁,从而造成内存泄漏

所以不推荐使用window对象进行通信。

4.3、 ES6模块化import/export

我们可以使用ES5的模块化规范import/export实现通信。

// a.js
export let a = undefined;
setTimeout(() => {
a = 1;
}, 1000) // b.js
import { a } from './a.js' setTimeout(() => {
console.log(a); // 打印1
}, 2000)

由于ES module采用的是符号绑定,所以就算export的值是一个基本数据类型的值,后续修改了也能访问到。

小结

上面介绍了总结了14种vue3的组件通信方式,包括:

  1. props
  2. defineEmits
  3. $attrs
  4. $ref + defineExpose
  5. $parent
  6. 作用域插槽
  7. v-model
  8. mitt
  9. vuex/pinia
  10. app.config.globalProperties
  11. provide/inject
  12. 浏览器本地存储storage
  13. 全局window对象
  14. ES6模块化import/export

希望能对大家有帮助!

Vue3的14种组件通信方式的更多相关文章

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

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

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

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

  3. vue中8种组件通信方式, 值得收藏!

    vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要,那么组件之间如何进行数据通信的呢? 首先我们需要知道在vue中组件之间存在什么样的关系, 才更容易理解他们的通信方式, 就 ...

  4. 【干货】Vue2.x 组件通信方式详解,这篇讲全了

    前言 vue是数据驱动视图更新的框架, 我们平时开发,都会把页面不同模块拆分成一个一个vue组件, 所以对于vue来说组件间的数据通信非常重要,那么组件之间如何进行数据通信的呢? 首先我们需要知道在v ...

  5. Vue中组件通信的几种方法(Vue3的7种和Vue2的12种组件通信)

    Vue3组件通信方式: props $emit expose / ref $attrs v-model provide / inject Vuex 使用方法: props 用 props 传数据给子组 ...

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

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

  7. Angular2 父子组件通信方式

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

  8. Android 进阶13:几种进程通信方式的对比总结

    不花时间打基础,你将会花更多时间解决那些不必要的问题. 读完本文你将了解: RPC 是什么 IDL 是什么 IPC 是什么 Android 几种进程通信方式 如何选择这几种通信方式 Thanks RP ...

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

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

  10. 服务器返回的14种常见HTTP状态码

    当我们从客户端向服务器发送请求时 服务器向我们返回状态码 状态码就是告诉我们服务器响应的状态 通过它,我们就可以知道当前请求是成功了还是出现了什么问题 状态码是由3位数字和原因短语组成的(比如最常见的 ...

随机推荐

  1. Centos 7 安装Redis5 详细步骤 备忘录笔记

    通过wget下载tar包 wget http://download.redis.io/releases/redis-5.0.5.tar.gz 解压包 tar -zxvf redis-5.0.5.tar ...

  2. 并发编程 - 线程同步(八)之自旋锁SpinLock

    前面对互斥锁Monitor进行了详细学习,今天我们将继续学习,一种更轻量级的锁--自旋锁SpinLock. 在 C# 中,SpinLock是一个高效的自旋锁实现,用于提供一种轻量级的锁机制.SpinL ...

  3. 无分类有tag

    1 2

  4. D pid(16916) tid(19140) 14:05:45 EdgeSnapFeature::PostExitSizeMove: WM_TWINVIEW_SHOW_GRIDLINES -> off

    D pid(16916) tid(19140) 14:05:45 EdgeSnapFeature::PostExitSizeMove: WM_TWINVIEW_SHOW_GRIDLINES -> ...

  5. C# 网页截图全攻略:三种技术与 Chrome 路径查找指南

    全局配置 string url = "https://blog.csdn.net/sunshineGGB/article/details/122316754"; 一.Puppete ...

  6. Win系统重装备忘

    蒙德,致态的盘坏块激增,似乎损坏到了系统文件:屏幕截屏会卡,关机后直接该块硬盘内的文件内容回滚,出现驱动报错要求重启... 然后尝试了DiskGenuis迁移系统,PE模式不能用,热迁移后似乎正常分区 ...

  7. nginx 禁止直接访问目录或文件

    前言 Nginx 默认是不允许列出整个目录的. 如需此功能,打开 nginx.conf 文件或你要启用目录浏览虚拟主机的配置文件,在 location server 或 http 段中加入 autoi ...

  8. Linux权限与特殊权限

    目录 5.1 权限讲解 5.1.1 什么是权限 5.1.2 为什么要管理权限 5.1.3 权限的分类 5.1.4 Linux的文件属于谁? 5.1.5 文件属主.属组.其他用户 5.1.6 所属者的表 ...

  9. TaskPyro:一个轻量级的 Python 任务调度和爬虫管理平台

    前言 推荐一款本人在使用的Python爬虫管理平台,亲测不错!!! TaskPyro 是什么? TaskPyro 是一个轻量级的 Python 任务调度平台,专注于提供简单易用的任务管理和爬虫调度解决 ...

  10. apisix~key-auth多消费的使用

    在 APISIX 中使用 key-auth 插件实现基于密钥的认证,以下是详细的配置步骤,包括如何保存密钥和证书,以及如何将这些信息分配给客户端 A 和 B. 场景说明 服务 C 是后端服务,需要通过 ...