【干货】Vue3 组件通信方式详解

vue3 · 浏览次数 : 17

小编点评

前言 组件通信是Vue中非常重要的技术之一,它的出现能够使我们非常方便的在不同组件之间进行数据的传递,以达到数据交互的效果。所以,学习组件通信技术是非常有必要的。 本文将总结Vue中关于组件通信的八种方式,帮助大家在使用Vue的过程中更加得心应手! 一、什么是组件通信 组件通信可以拆分为两个部分: 1. 组件通信都知道组件是vue最强大的功能之一,vue中每一个.vue文件我们都可以视之为一个组件,简单来说组件就是对UI结构的复用。 2. 通信指的是发送者通过某种媒体以某种格式来传递信息到收信者以达到某个目的。 广义上,任何信息的交通都是通信。而组件间通信即指组件(.vue)通过某种方式来传递信息以达到某个目的。 二、为什么要进行组件通信 通信的本质是信息同步,共享。回到vue中,每个组件之间的都有独自的作用域,组件间的数据是无法共享的但实际开发工作中我们常常需要让组件之间共享数据,这也是组件通信的目的要让它们互相之间能进行通讯,这样才能实现数据间的交互,完成某种功能的开发。 三、组件通信的分类 组件间通信的分类可以分成以下: 1. 父子组件之间的通信 2. 兄弟组件之间的通信 3. 祖孙与后代组件之间的通信 4. 非关系组件间之间的通信 他们之间的关系如下图: 目前最常用是props/$emit 和 vuex/pinia ,接下来是 provide/inject,其他不建议使用;实际项目中,简单父子组件传递采用props/$emit ,涉及全局共享的数据一般采用 vuex/pinia 结合存储对象localStorage/sessionStorage使用。 四、Vue3 的八种组件通信方式 1. props 2. $emit 3. expose / ref 4. attrs 5. v-model 6. provide / inject 7. Vuex 8. mitt 五、Vue3 八种通信方式用法讲解 1. props 用 props 传数据给子组件有两种方法,如下方法一,setup() 方法写法 // Parent.vue 传送 // Child.vue 接收 方法二,setup 语法糖 // Parent.vue 传送 // Child.vue 接收 注意:如果父组件是setup(),子组件setup 语法糖写法的话,是接收不到父组件里 data 的属性,只能接收到父组件里 setup 函数里传的属性。如果父组件是setup 语法糖写法,子组件setup()方法写法,可以通过 props 接收到 data 和 setup 函数里的属性,但是子组件要是在 setup 里接收,同样只能接收到父组件中 setup 函数里的属性,接收不到 data 里的属性。官方也说了,既然用了 3,就不要写 2 了,所以不推荐setup()方法写法。下面的例子,一律只用语法糖的写法。 2. $emit // Child.vue 派发 // Parent.vue 响应 3. expose / ref 父组件获取子组件的属性或者调用子组件方法。 // Child.vue // Parent.vue 4. attrs attrs:包含父作用域里除 class 和 style 除外的非 props 属性集合。 // Parent.vue 传送 // Child.vue 接收 5. v-model 可以支持多个数据双向绑定 // Parent.vue // Child.vue 6. provide / Inject provide:可以让我们指定想要提供给后代组件的数据或 inject:在任何后代组件中接收想要添加在这个组件上的数据,不管组件嵌套多深都可以直接拿来用 // Parent.vue // Child.vue 7. Vuex store/index.js import { createStore } from "vuex"; export default createStore({ state: { count: 1 }, getters: { getCount: state => state.count }, mutations: { add(state) { state.count++; } } }); // main.js import { createApp } from "vue"; import App from "./App.vue"; import store from "./store"; createApp(App).use(store).mount("#app"); // Page.vue // 方法一 直接使用
{{ $store.state.count }}
// 方法二 获取 8. mitt Vue3 中没有了 EventBus 跨组件通信,但是现在有了一个替代的方案 mitt.js,原理还是 EventBus。 先安装 npm i mitt -S 然后像以前封装 bus 一样,封装一下mitt.js import mitt from 'mitt' export default mitt 然后两个组件之间通信的使用 // 组件 A // 组件 B

正文

前言

毫无疑问,组件通信是Vue中非常重要的技术之一,它的出现能够使我们非常方便的在不同组件之间进行数据的传递,以达到数据交互的效果。所以,学习组件通信技术是非常有必要的,本文将总结Vue中关于组件通信的八种方式,帮助大家在使用Vue的过程中更加得心应手!

如果文中有不对、疑惑的地方,欢迎在评论区留言指正!!

一、什么是组件通信

在开始之前我们需要明白什么是组件通信,组件通信可以拆分为两个部分:

  • 组件
  • 通信

都知道组件是vue最强大的功能之一,vue中每一个.vue文件我们都可以视之为一个组件,简单来说组件就是对UI结构的复用。

通信指的是发送者通过某种媒体以某种格式来传递信息到收信者以达到某个目的。广义上,任何信息的交通都是通信。而组件间通信即指组件(.vue)通过某种方式来传递信息以达到某个目的,举个栗子我们在使用UI框架中的table组件,可能会往table组件中传入某些数据,这个本质就形成了组件之间的通信

二、为什么要进行组件通信

通信的本质是信息同步,共享。回到vue中,每个组件之间的都有独自的作用域,组件间的数据是无法共享的但实际开发工作中我们常常需要让组件之间共享数据,这也是组件通信的目的要让它们互相之间能进行通讯,这样才能实现数据间的交互,完成某种功能的开发。

三、组件通信的分类

组件间通信的分类可以分成以下

  • 父子组件之间的通信
  • 兄弟组件之间的通信
  • 祖孙与后代组件之间的通信
  • 非关系组件间之间的通信

他们之间的关系如下图:

组件

目前最常用是props/$emitvuex/pinia ,接下来是 provide/inject,其他不建议使用;
实际项目中,简单父子组件传递采用props/$emit ,涉及全局共享的数据一般采用 vuex/pinia 结合存储对象localStorage/sessionStorage使用。

Vue3 组件通信方式

四、Vue3 的八种组件通信方式

  • props
  • $emit
  • expose / ref
  • $attrs
  • v-model
  • provide / inject
  • Vuex
  • mitt

五、Vue3 八种通信方式用法讲解

1. props

用 props 传数据给子组件有两种方法,如下

方法一,setup() 方法写法

// Parent.vue 传送
<child :msg1="msg1" :msg2="msg2"></child>
<script>
import child from "./child.vue"
import { ref, reactive } from "vue"
export default {
    data(){
        return {
            msg1:"这是传级子组件的信息1"
        }
    },
    setup(){
        // 创建一个响应式数据
        
        // 写法一 适用于基础类型  ref 还有其他用处,下面章节有介绍
        const msg2 = ref("这是传级子组件的信息2")
        
        // 写法二 适用于复杂类型,如数组、对象
        const msg2 = reactive(["这是传级子组件的信息2"])
        
        return {
            msg2
        }
    }
}
</script>

// Child.vue 接收
<script>
export default {
  props: ["msg1", "msg2"],// 如果这行不写,下面就接收不到
  setup(props) {
    console.log(props) // { msg1:"这是传给子组件的信息1", msg2:"这是传给子组件的信息2" }
  },
}
</script>

方法二,setup 语法糖

// Parent.vue 传送
<child :msg2="msg2"></child>
<script setup>
    import child from "./child.vue"
    import { ref, reactive } from "vue"
    const msg2 = ref("这是传给子组件的信息2")
    // 或者复杂类型
    const msg2 = reactive(["这是传级子组件的信息2"])
</script>

// Child.vue 接收
<script setup>
    // 不需要引入 直接使用
    // import { defineProps } from "vue"
    const props = defineProps({
        // 写法一
        msg2: String
        // 写法二
        msg2:{
            type:String,
            default:""
        }
    })
    console.log(props) // { msg2:"这是传级子组件的信息2" }
</script>

注意:

如果父组件是setup(),子组件setup 语法糖写法的话,是接收不到父组件里 data 的属性,只能接收到父组件里 setup 函数里传的属性。

如果父组件是setup 语法糖写法,子组件setup()方法写法,可以通过 props 接收到 data 和 setup 函数里的属性,但是子组件要是在 setup 里接收,同样只能接收到父组件中 setup 函数里的属性,接收不到 data 里的属性

官方也说了,既然用了 3,就不要写 2 了,所以不推荐setup()方法写法。下面的例子,一律只用语法糖的写法。

2. $emit

// Child.vue 派发
<template>
    // 写法一
    <button @click="emit('myClick')">按钮</buttom>
    // 写法二
    <button @click="handleClick">按钮</buttom>
</template>
<script setup>
    
    // 方法一 适用于Vue3.2版本 不需要引入
    // import { defineEmits } from "vue"
    // 对应写法一
    const emit = defineEmits(["myClick","myClick2"])
    // 对应写法二
    const handleClick = ()=>{
        emit("myClick", "这是发送给父组件的信息")
    }
    
    // 方法二 不适用于 Vue3.2版本,该版本 useContext()已废弃
    import { useContext } from "vue"
    const { emit } = useContext()
    const handleClick = ()=>{
        emit("myClick", "这是发送给父组件的信息")
    }
</script>

// Parent.vue 响应
<template>
    <child @myClick="onMyClick"></child>
</template>
<script setup>
    import child from "./child.vue"
    const onMyClick = (msg) => {
        console.log(msg) // 这是父组件收到的信息
    }
</script>

3. expose / ref

父组件获取子组件的属性或者调用子组件方法。

// Child.vue
<script setup>
    // 方法一 不适用于Vue3.2版本,该版本 useContext()已废弃
    import { useContext } from "vue"
    const ctx = useContext()
    // 对外暴露属性方法等都可以
    ctx.expose({
        childName: "这是子组件的属性",
        someMethod(){
            console.log("这是子组件的方法")
        }
    })
    
    // 方法二 适用于Vue3.2版本, 不需要引入
    // import { defineExpose } from "vue"
    defineExpose({
        childName: "这是子组件的属性",
        someMethod(){
            console.log("这是子组件的方法")
        }
    })
</script>

// Parent.vue  注意 ref="comp"
<template>
    <child ref="comp"></child>
    <button @click="handlerClick">按钮</button>
</template>
<script setup>
    import child from "./child.vue"
    import { ref } from "vue"
    const comp = ref(null)
    const handlerClick = () => {
        console.log(comp.value.childName) // 获取子组件对外暴露的属性
        comp.value.someMethod() // 调用子组件对外暴露的方法
    }
</script>

4. attrs

attrs:包含父作用域里除 class 和 style 除外的非 props 属性集合

// Parent.vue 传送
<child :msg1="msg1" :msg2="msg2" title="3333"></child>
<script setup>
    import child from "./child.vue"
    import { ref, reactive } from "vue"
    const msg1 = ref("1111")
    const msg2 = ref("2222")
</script>

// Child.vue 接收
<script setup>
    import { defineProps, useContext, useAttrs } from "vue"
    // 3.2版本不需要引入 defineProps,直接用
    const props = defineProps({
        msg1: String
    })
    // 方法一 不适用于 Vue3.2版本,该版本 useContext()已废弃
    const ctx = useContext()
    // 如果没有用 props 接收 msg1 的话就是 { msg1: "1111", msg2:"2222", title: "3333" }
    console.log(ctx.attrs) // { msg2:"2222", title: "3333" }
    
    // 方法二 适用于 Vue3.2版本
    const attrs = useAttrs()
    console.log(attrs) // { msg2:"2222", title: "3333" }
</script>

5. v-model

可以支持多个数据双向绑定

// Parent.vue
<child v-model:key="key" v-model:value="value"></child>
<script setup>
    import child from "./child.vue"
    import { ref, reactive } from "vue"
    const key = ref("1111")
    const value = ref("2222")
</script>

// Child.vue
<template>
    <button @click="handlerClick">按钮</button>
</template>
<script setup>
    
    // 方法一  不适用于 Vue3.2版本,该版本 useContext()已废弃
    import { useContext } from "vue"
    const { emit } = useContext()
    
    // 方法二 适用于 Vue3.2版本,不需要引入
    // import { defineEmits } from "vue"
    const emit = defineEmits(["key","value"])
    
    // 用法
    const handlerClick = () => {
        emit("update:key", "新的key")
        emit("update:value", "新的value")
    }
</script>

6. provide / inject

provide / inject 为依赖注入

provide:可以让我们指定想要提供给后代组件的数据或

inject:在任何后代组件中接收想要添加在这个组件上的数据,不管组件嵌套多深都可以直接拿来用

// Parent.vue
<script setup>
    import { provide } from "vue"
    provide("name", "RDIF")
</script>

// Child.vue
<script setup>
    import { inject } from "vue"
    const name = inject("name")
    console.log(name) // RDIF
</script>

7. Vuex

// store/index.js
import { createStore } from "vuex"
export default createStore({
    state:{ count: 1 },
    getters:{
        getCount: state => state.count
    },
    mutations:{
        add(state){
            state.count++
        }
    }
})

// main.js
import { createApp } from "vue"
import App from "./App.vue"
import store from "./store"
createApp(App).use(store).mount("#app")

// Page.vue
// 方法一 直接使用
<template>
    <div>{{ $store.state.count }}</div>
    <button @click="$store.commit('add')">按钮</button>
</template>

// 方法二 获取
<script setup>
    import { useStore, computed } from "vuex"
    const store = useStore()
    console.log(store.state.count) // 1

    const count = computed(()=>store.state.count) // 响应式,会随着vuex数据改变而改变
    console.log(count) // 1 
</script>

8. mitt

Vue3 中没有了 EventBus 跨组件通信,但是现在有了一个替代的方案 mitt.js,原理还是 EventBus。

先安装 npm i mitt -S

然后像以前封装 bus 一样,封装一下

mitt.js
import mitt from 'mitt'
const mitt = mitt()
export default mitt

然后两个组件之间通信的使用

// 组件 A
<script setup>
import mitt from './mitt'
const handleClick = () => {
    mitt.emit('handleChange')
}
</script>

// 组件 B 
<script setup>
import mitt from './mitt'
import { onUnmounted } from 'vue'
const someMethed = () => { ... }
mitt.on('handleChange',someMethed)
onUnmounted(()=>{
    mitt.off('handleChange',someMethed)
})
</script>

六、参考资料

vue.js: https://cn.vuejs.org/

vuex是什么:https://vuex.vuejs.org/zh/

工作中要使用Git,看这篇文章就够了:http://www.guosisoft.com/article/detail/410508049313861

企业数字化转型如何做?看过来:http://www.guosisoft.com/article/detail/408745545576517

Vue2.x 组件通信方式:http://www.guosisoft.com/article/detail/411234710110277

【保姆级教程】Vue项目调试技巧:http://www.guosisoft.com/article/detail/430312211521605

Vue 前端开发团队风格指南(史上最全):http://www.guosisoft.com/article/detail/415491255230533

国思RDIF低代码快速开发平台(支持vue2、vue3):http://www.guosisoft.com/article/detail/557095625134149

七、结语

如果本文对你有一点点帮助,点个赞支持一下吧,你的每一个【赞】都是我创作的最大动力 _

更多技术文章请往:

http://www.guosisoft.com/article

http://www.rdiframework.net/article

大家一起共同交流和进步呀!!

与【干货】Vue3 组件通信方式详解相似的内容:

【干货】Vue3 组件通信方式详解

毫无疑问,组件通信是Vue中非常重要的技术之一,它的出现能够使我们非常方便的在不同组件之间进行数据的传递,以达到数据交互的效果。所以,学习组件通信技术是非常有必要的,本文将总结Vue中关于组件通信的八种方式,帮助大家在使用Vue的过程中更加得心应手! 如果文中有不对、疑惑的地方,欢迎在评论区留言指正...

这个vue3的后台管理系统虽然简洁但不简单

今天介绍一个新的Vue后台管理框架,相比其他后台功能丰富管理系统,这个后台管理系统可以用干净简洁来形容——Nova-admin Nova-admin Nova-admin 是一个基于Vue3、Vite5等最新技术的后台管理平台。用简单的方式实现完整功能,并尽可能的考虑代码规范,易读易理解无过度封装,

【干货分享】.NET人脸识别解决方案

前言 前段时间有同学在DotNetGuide技术社区交流群提问:.NET做人脸识别功能有什么好的解决方案推荐的吗?今天大姚给大家推荐2款.NET开源、免费、跨平台、使用简单的人脸识别库,希望可以帮助到有需要的同学。 人脸识别应用场景 现如今人脸识别应用场景比较广泛如:安防监控、人脸门禁系统、考勤管理

【干货】质量管理是什么?管什么?如何管?

1、引言 质量管理,作为现代企业管理体系的核心组成部分,对提升企业竞争力、确保产品质量和客户满意度具有至关重要的作用。因此,理解质量管理的本质,以及它管理的具体内容,对于任何一个追求长期发展的组织或管理者来说都是至关重要的。 本文将围绕“质量管理是什么?管什么?”这一主题,进行一个简单的分享,希望能

[转帖]【干货来袭】数据库mysql迁移问题汇总

https://www.modb.pro/db/45975 1.service mysqld start出错,mysqld启动不了,解决mysqld: unrecognized service错误的方法如下: a. 复制配置文件 [root@localhost mysql] cp support-f

【干货】华为云图数据库GES技术演进

大规模图数据无处不在,图查询、分析和表示学习已成为大数据和AI的核心部分之一。特别是知识图谱和图神经网络的发展,Graph已成为未来AI的基础。

纯干货!一文get昇腾Ascend C编程入门全部知识点

一文get昇腾Ascend C编程入门全部知识点,只需要了解C++编程、理解对列通信与内存申请释放机制、通过调用相应的计算接口与搬运接口,就可以高效写出运行在昇腾AI处理器上的高性能算子。

干货!超实用的 Linux 初始化脚本

咸鱼今天给大家分享一个无论是学习还是工作中都很实用的 Linux 系统初始化脚本,其实就是各种命令的集合 完整代码在文章最后哦 定义相关变量 配置 yum 镜像源 获取阿里云 yum 镜像源 判断函数是否执行成功 写入一行配置 修改配置 配置系统时区 配置 dns 服务器 修改最大文件描述符限制 关

Linux 干货整理

> 博客地址:https://www.cnblogs.com/zylyehuo/ # 如果虚拟机开机没有 ip 怎么办 ```bash 1.vim编辑网卡配置文件,修改如下参数 [root@s25linux tmp]# cd /etc/sysconfig/network-scripts/ vim修改

躬身入局,干货分享,2023年春招后端技术岗(Python)面试实战教程,Offer今始为君发

早春二月,研发倍忙,杂花生树,群鸥竟飞。为什么?因为春季招聘,无论是应届生,还是职场老鸟,都在摩拳擦掌,秣马厉兵,准备在面试场上一较身手,既分高下,也决Offer,本次我们打响春招第一炮,躬身入局,让2023年的第一个Offer来的比以往快那么一点点。