一文详解Vue3中的14种组件通信方式

 更新时间:2025年01月10日 10:46:41   作者:程序员小寒  
对于日常使用vue3开发项目的前端小伙伴来说,组件通信方式可以说是必会的基本功,今天带大家一起盘下vue3中的14种通信方式,希望对大家有所帮助

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

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

一:父子通信

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可以让子组件的值传递到父组件中。

其用法如下:

先在子组件中用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>

在父组件中通过@符 + 事件名监听子组件发射 出来的事件,并接收其传过来的值。

// 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> 组件中要暴露出去的属性,它两一起配合使用,就能实现父子组件的通信。

其用法如下:

在子组件中通过defineExpose暴露一个update方法。

// Child.vue
<script setup>
defineExpose({
    update(val) {
        console.log('父组件传递过来的值', val);
    }
})
</script>

在父组件中通过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的效果。

用法如下:

安装mitt

npm install mitt

初始化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提供的可以跨层级通信的方式。

其用法如下:

父组件/根组件中定义provide提供数据

// App.vue
<script setup>
import { ref, provide } from 'vue';

const name = ref('sam');
provide('name', name)
</script>

子组件/孙子组件中使用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作为一个全局对象,当然也可以使用它来通信了,不过它既然谁都可以访问到,就存在如下问题:

  • 命令冲突问题;
  • 难以追踪数据修改,可维护性差;
  • 挂在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的值是一个基本数据类型的值,后续修改了也能访问到。

以上就是一文详解Vue3中的14种组件通信方式的详细内容,更多关于Vue3组件通信方式的资料请关注脚本之家其它相关文章!

相关文章

  • 在Vue3项目中安装和配置Three.js的操作代码

    在Vue3项目中安装和配置Three.js的操作代码

    Three.js是一个轻量级的WebGL封装库,用于在浏览器中渲染复杂的3D图形,它提供了便捷的API,可以快速构建3D场景、对象和动画,Vue.js是一个渐进式JavaScript框架,擅长构建用户界面,本文给大家介绍了在Vue3项目中安装和配置Three.js的操作,需要的朋友可以参考下
    2024-12-12
  • JavaScript 沙箱探索

    JavaScript 沙箱探索

    这篇文章主要介绍了JavaScript 沙箱探索,沙箱是基于 event bus 形式的通信实现上层的功能,文章的例子选择接口实现了 web worker 与 quickjs 的 EventEmitter,,需要的朋友可以参考一下
    2021-10-10
  • Vue实用功能之实现拖拽元素、列表拖拽排序

    Vue实用功能之实现拖拽元素、列表拖拽排序

    在日常开发中,特别是管理端,经常会遇到要实现拖拽排序的效果,下面这篇文章主要给大家介绍了关于Vue实用功能之实现拖拽元素、列表拖拽排序的相关资料,需要的朋友可以参考下
    2022-10-10
  • Vuejs开发环境搭建及热更新【推荐】

    Vuejs开发环境搭建及热更新【推荐】

    Vue.js是目前很火的一个前端框架,采用MVVM模式设计,它是以数据驱动和组件化的思想构建的。本文重点给大家介绍Vuejs开发环境搭建及热更新的相关知识,需要的朋友参考下吧
    2018-09-09
  • vue中的mescroll搜索运用及各种填坑处理

    vue中的mescroll搜索运用及各种填坑处理

    这篇文章主要介绍了vue中的mescroll搜索运用及各种填坑处理,文中通过代码给大家讲解了mescroll vue使用,感兴趣的朋友跟随小编一起看看吧
    2019-10-10
  • Vue3快速实现文件上传OSS的方法详解

    Vue3快速实现文件上传OSS的方法详解

    这篇文章给大家介绍了Vue3快速实现文件上传OSS的方法,上传文件可以说是经典的需求了,在后台管理项目中随处可见,一般是由前端进行文件上传,然后再由后端去处理,本文旨在实现上传功能,不考虑额外的功能(如文件尺寸限制),感兴趣的朋友可以参考下
    2024-01-01
  • vue中调用HTTP请求的详细步骤

    vue中调用HTTP请求的详细步骤

    这篇文章主要介绍了vue中调用HTTP请求的详细步骤,文中通过代码示例给大家讲解的非常详细,对大家的学习或工作有一定帮助,需要的朋友可以参考下
    2024-07-07
  • vue实现微信公众号h5跳转小程序的示例代码

    vue实现微信公众号h5跳转小程序的示例代码

    本文主要介绍了vue实现微信公众号h5跳转小程序的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • VSCode使React Vue代码调试变得更爽

    VSCode使React Vue代码调试变得更爽

    这篇文章主要为大家介绍了VSCode使React Vue代码调试变得更爽的使用方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • vue滚动固定顶部及修改样式的实例代码

    vue滚动固定顶部及修改样式的实例代码

    这篇文章主要介绍了vue滚动固定顶部及修改样式,本文给大家提到了滚动固定位置有多种方法,感兴趣的朋友跟随小编一起看看吧
    2019-05-05

最新评论