vue3组件间通信

目录

父子组件

1.props(父传子)

2.emit(子传父)

3.ref(子传父)

4.provide / inject(祖孙、父子组件)

兄弟组件

1.mitt

使用方法1:单文件方法

使用方法2:全局挂载使用


父子组件

1.props(父传子)

props是最常见的父子组件通信的方式

父组件:

  <Demo09b msg="我是父组件!!!"></Demo09b>

子组件:(Demo09b组件)

在单文件中使用<script setup> ,props可以使用defineProps( )来定义

import {defineProps} from "vue";
//为传过来的属性设置类型与默认值
const props =defineProps({
  msg:{  
    type:String,
    default:'我是默认值'
  }
}
//或者只限定类型
const props = defineProps({
  msg: String,
  xx属性: xx类型
})
  )
//或者直接接受,不设定类型与默认值
const props = defineProps(['msg'])

对于取值:setup中要通过props.msg取到,模板中直接msg取到 

2.emit(子传父)

emit是最常见的用于子组件向父组件传递消息的方法。

vue3使用使用defineEmits来声明emit,它接收内容与emit选项是一致的。

(1)用法一:给父组件发送自定义事件
// ----------子组件--------
  <button @click="btn">点击</button>
<script setup>
import {defineEmits} from 'vue'
const emit = defineEmits(['emit']) //数组里可以有多个自定义方法名
//或者使用ts约束自定义方法的参数
const emit = defineEmits<{
  (e:'getAge',age:number):void //设置自定义函数名称,参数类型与返回值类型
  // 可在此设置第二个自定义函数
}>()

function btn() {
  emit('getAge',18)
}
</script>
 

// ---------父级组件中--------

// 在父级组件中,使用子级的自定义事件,在html中去写@自定义事件名称=事件名称(就是在子组件中emits的第一个参数)
  <HelloWorld @getAge="handleAge"/>
<script setup>
import HelloWorld from '@/components/HelloWorld'
// 函数中data是个形参,为子级传递过来的数据
const handleAge = function (data) {
  console.log(data)
}
</script>
(2)用法二:使用modelValue直接更新父组件数据

父组件:

//结构  
  <CHild v-model:test="test"></CHild>

//逻辑
let test =ref()



子组件

//逻辑
const props = defineProps({
test:'',
})
const emit = defineEmits(['update:test']);  //这个test就是接收的props
const resetTest =() =>{
//更新test给父组件
emit('update:test','最新数据')
}

这样父组件不需要自定义事件就能接受到最新的test数据。! 

3.ref(子传父)

 【子组件内】

定义方法或变量,使用defineExpose暴露出去

import {defineExpose} from "vue"

//初始化表单方法
const resetForm = () => {
  formRef.value.resetFields()
}
//暴露方法
defineExpose({resetForm})

【父组件内】

定义ref,绑定给子组件

父组件调用子组件的方法:

4.provide / inject(祖孙、父子组件)

这两个都只能在setup( )中调用

在多级嵌套的组件体系中,某一级的外层组件可以通过provide属性向其下任意的一级子组件提供一个依赖,不管层级有多深;而某一级的子组件则可以通过inject属性接收来自其上任意一级父组件提供的依赖。 注意provideinject需要一起使用,通过provide / inject互相传递的值在任意组件修改了,其他组件也同步

举个例子:有三个组件,分别是爷爷,爸爸,孙子。

// 嵌套条件
<yeye>
  <baba>
    <sunzi></sunzi>
  </baba>
</yeye>

定义爷爷组件

<script setup lang="ts">
import {provide} from "vue"
let my = ref('我是爷爷')
//传入的数据其他组件可改(当前组件也会同步)
provide('info',my) //传递 键 ,值
//让传入的数据在其他组件中不可修改
provide('info',readonly(my))
</script>

定义爸爸、孙子组件(写法都一样)

<script setup lang="ts">
import {inject} from 'vue'
const info = inject<Ref<string>>('info') //通过键取得值
info!.value = '1212' //修改得到的值(使用非空断言操作符就不会报错)
</script>

兄弟组件

1.mitt

vue到3.0之后好像取消了bus全局事件总线,选择使用mitt作为兄弟组件间通信和传参的方式。mitt的使用方法有两种:可以单独创建一个文件,哪里要用就引入它;也可以 main.js 中挂载全局属性;

使用mitt,首先要安装mitt库

npm i mitt

使用方法1:单文件方法

在单独的文件中暴露出事件总线对象

import mitt from "mitt"
const Mit = mitt()

// 由于必须要拓展ComponentCustomProperties类型才能获得类型提示
declare module "vue" {
    export interface ComponentCustomProperties {
        bus: typeof Mit
    }
}
export default Mit

在指定组件中导入并使用它

<template>
  <button @click="sendHomeContent">send</button>  
</template>

文件1:
<script setup>
// 导入事件总线
  import mitt from "./utils/eventbus.js";  
  sendHomeContent(){
    // 触发自定义总线why,并传入一个对象(图方便就用上面第一种写法了)
     mitt.emit("why",{name:'why',age:19})
  }
</script>

文件2:
<script setup>
// 导入事件总线
import mitt from "./utils/eventbus.js";

// 在创建vue实例时,注册why事件总线
// res就是传过来的数据
    mitt.on("why",res=>{
        console.log("HomeContent接收到得About发送得数据了:",res);
}
</script>

使用方法2:全局挂载使用

全局总线,vue 入口文件 main.js 中挂载全局属性

import { createApp } from 'vue'
import App from './App.vue'
import mitt from 'mitt'
 
const Mit = mitt()//创建mitt实例
 
//TypeScript注册
// 由于必须要拓展ComponentCustomProperties类型才能获得类型提示
declare module "vue" {
    export interface ComponentCustomProperties {
        $Bus: typeof Mit
    }
}
 
const app = createApp(App)
 
//  vue3 中使用 app.config.globalProperties,替代了vue2中的Vue.prototype,用于注册能够被应用内所有组件实例访问到的全局属性的对象 
app.config.globalProperties.$Bus = Mit //使用的时候就是xx.$Bus.on或者xx.$Bus.emit
 
app.mount('#app')

3使用方法通过emit派发, on 方法添加事件,off 方法移除,clear 清空所有

A组件派发(emit)

<template>
        <button @click="emit1">emit1</button>
</template>
 
<script setup lang='ts'>
import { getCurrentInstance } from 'vue'
const instance = getCurrentInstance(); //获得当前组件实例对象
const emit1 = () => {
    instance?.proxy?.$Bus.emit('on-num', 100) //参数1:自定义方法名,参数二:要传的数据
}

</script>


B组件监听(on)


 <script setup lang='ts'>
import { getCurrentInstance } from 'vue'
const instance = getCurrentInstance()
instance?.proxy?.$Bus.on('on-num', (num) => {
    console.log(num)
})
</script>
 

监听所有事件( on("*") )

instance?.proxy?.$Bus.on('*',(type,num)=>{
    console.log(type,num,'===========>B')
})

移除监听事件(off)

const Fn = (num: any) => {
    console.log(num, '===========>B')
}
instance?.proxy?.$Bus.on('on-num',Fn)//listen
instance?.proxy?.$Bus.off('on-num',Fn)//unListen


清空所有监听(clear)

instance?.proxy?.$Bus.all.clear() 


原文链接:https://blog.csdn.net/qq1195566313/article/details/125453908

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值