vue3组件通信方式——基础(props、自定义事件、全局事件总线$bus、provide&inject)详解

一、通信方式之props(父传子)

父组件中引入子组件,在子组件标签上绑定属性。

子组件通过 defineProps() 方法进行接收。

<template>
  <div class="box">
    <h1>props:我是父组件曹操</h1>
    <hr />
    <Child info="我是曹操" :money="money"></Child>
  </div>
</template>

<script setup lang="ts">
//props:可以实现父子组件通信,props数据还是只读的!!!
import Child from "./Child.vue";
import { ref } from "vue";
let money = ref(10000);
</script>

<style scoped>
.box {
  width: 100vw;
  height: 400px;
  background: yellowgreen;
}
</style>
<template>
  <div class="son">
       <h1>我是子组件:曹植</h1>
       <p>{{props.info}}</p>
       <p>{{props.money}}</p>
      <!--props可以省略前面的名字--->
       <p>{{info}}</p>
       <p>{{money}}</p>
  </div>
</template>

<script setup lang="ts">
//需要使用到defineProps方法去接受父组件传递过来的数据
//defineProps是Vue3提供方法,不需要引入直接使用
let props = defineProps(['info','money']); //数组|对象写法都可以
console.log(props.info,props.money)
</script>

<style scoped>
.son{
  width: 400px;
  height: 200px;
  background: hotpink;
}
</style>

二、通信方式之自定义事件(子传父)

父组件在子组件标签上绑定自定义事件

子组件通过 defineEmits() 方法进行触发父组件绑定的自定义事件

<template>
  <div>
    <h1>父组件</h1>
    <h2>{{ sonData }}</h2>
    <!-- 绑定自定义事件xxx:实现子组件给父组件传递数据 -->
    <Event2 @getSonData="handle"></Event2>
  </div>
</template>

<script setup lang="ts">
import {ref} from "vue"
const sonData=ref('')
//引入子组件
import Event2 from './Event2.vue';
const handle=(data: string)=>{
  sonData.value=data
}
</script>

<style scoped>
</style>
<template>
  <div class="child">
    <p>我是子组件2</p>
    <button @click="info">给父组件传值</button>
  </div>
</template>

<script setup lang="ts">
//利用defineEmits方法返回函数触发自定义事件
//defineEmits方法不需要引入直接使用
let $emit = defineEmits(['getSonData']);
const info=()=>{
  $emit('getSonData','子组件传递的值')
}
</script>

<style scoped>
.child {
  width: 400px;
  height: 200px;
  background: pink;
}
</style>

三、通信方式之全局事件总线(组件间通信)

全局事件总线是用的 mitt 插件,需要插件安装

$ npm install --save mitt

在src目录下创建bus/index.ts

//bus/index.ts
//引入mitt插件:mitt一个方法,方法执行会返回bus对象
import mitt from 'mitt';
const $bus = mitt();
export default $bus;

<template>
  <div class="box">
    <h1>父组件:全局事件总线$bus</h1>
    <hr />
    <div class="container">
      <Child1></Child1>
      <Child2></Child2>
    </div>
  </div>
</template>

<script setup lang="ts">
//引入子组件
import Child1 from "./Child1.vue";
import Child2 from "./Child2.vue";
</script>

<style scoped>
.box {
  width: 100vw;
  height: 400px;
  background: yellowgreen;
}
.container{
  display: flex;
  justify-content: space-between;
}
</style>
<template>
  <div class="child1">
    <h3>我是子组件1</h3>
    <h2>{{carName}}</h2>
  </div>
</template>

<script setup lang="ts">
import $bus from "../../bus";
//组合式API函数
import { onMounted ,ref} from "vue";
const carName=ref()
//组件挂载完毕的时候,当前组件绑定一个事件,接受将来兄弟组件传递的数据
onMounted(() => {
  //第一个参数:即为事件类型  第二个参数:即为事件回调
  $bus.on("car", (data) => {
    console.log(data.car);
    carName.value=data.car
  });
});

</script>

<style scoped>
.child1 {
  width: 300px;
  height: 300px;
  background: hotpink;
}
</style>
<template>
  <div class="child2">
     <h2>我是子组件2</h2>
     <button @click="handler">点击我给兄弟送一台法拉利</button>
  </div>
</template>

<script setup lang="ts">
//引入$bus对象
import $bus from '../../bus';
//点击按钮回调
const handler = ()=>{
  $bus.emit('car',{car:"法拉利"});
}
</script>

<style scoped>
.child2{
  width: 300px;
  height: 300px;
  background: skyblue;
}
</style>

三、通信方式之provide&inject(组件间通信 祖孙通信)

vue3提供provide(提供)与inject(注入),可以实现隔辈组件传递数据
provide('name',data)
两个参数:

第一个参数就是提供的数据key
第二个参数:祖先组件提供数据

let name = inject('name')

一个参数:即为祖先提供数据的key

<template>
  <div class="box">
    <h1>祖先组件    Provide与Inject{{car}}    </h1>
    <hr />
    <Child></Child>
  </div>
</template>

<script setup lang="ts">
import Child from "./Child.vue";
//vue3提供provide(提供)与inject(注入),可以实现隔辈组件传递数据
import { ref, provide } from "vue";
let car = ref("法拉利");
//祖先组件给后代组件提供数据
//两个参数:第一个参数就是提供的数据key
//第二个参数:祖先组件提供数据
provide("TOKEN", car);
</script>

<style scoped>
.box {
  width: 100vw;
  height: 600px;
  background: skyblue;
}
</style>
<template>
  <div class="child">
     <h1>我是子组件1</h1>
     <Child></Child>
  </div>
</template>

<script setup lang="ts">
import Child from './GrandChild.vue';
</script>

<style scoped>
.child{
  width: 300px;
  height: 400px;
  background: yellowgreen;
}
</style>
<template>
  <div class="child1">
    <h1>孙子组件</h1>
    <p>{{car}}</p>
    <button @click="updateCar">更新数据</button>
  </div>
</template>

<script setup lang="ts">
import {inject} from 'vue';
//注入祖先组件提供数据
//需要参数:即为祖先提供数据的key
let car = inject('TOKEN');
const updateCar = ()=>{
   car.value  = '自行车';
}
</script>

<style scoped>
.child1 {
  width: 200px;
  height: 200px;
  background: red;
}
</style>

四、组件通信方式之useAttrs (父传子)

useAttrs方法获取组件标签身上属性与事件

<template>
  <div>
    <h1>父组件:useAttrs</h1>
    <el-button type="primary" size="small" :icon="Edit"></el-button>
    <!-- 自定义组件 -->
    <HintButton type="primary" size="small" :icon="Edit" title="编辑按钮" @click="handler" @xxx="handler"></HintButton>
  </div>
</template>

<script setup lang="ts">
//vue3框架提供一个方法useAttrs方法,它可以获取组件身上的属性与事件!!!
//图标组件
import {Edit} from "@element-plus/icons-vue";
import HintButton from "./HintButton.vue";
//按钮点击的回调
const handler = ()=>{
  alert(12306);
}
</script>

<style scoped>
</style>
<template>
  <h2>自定义子组件</h2>
  <div :title="title">
     <el-button :="$attrs"></el-button>   
  </div>
</template>

<script setup lang="ts">
//引入useAttrs方法:获取组件标签身上属性与事件
import {useAttrs} from 'vue';
//此方法执行会返回一个对象
let $attrs = useAttrs();

//万一用props接受title
let props =defineProps(['title']);
//props与useAttrs方法都可以获取父组件传递过来的属性与属性值
//但是props接受了useAttrs方法就获取不到了
console.log($attrs);
</script>

<style scoped>
</style>

五、组件通信方式之ref(获取子组件的属性及方法)、$parent(获取父组件的属性及方法)

父组件:在子组件标签上绑定ref,必须要定义一个与ref绑定同名的属性【let son = ref()】  用来后期获取组件实例【son.value.money】

子组件:要想别人调用自己的方法和属性必须暴露出去【 defineExpose({money,fly}) 】

<template>
  <div class="box">
    <h1>我是父亲曹操:{{money}}</h1>
    <button @click="handler">找我的儿子曹植借10元</button>
    <hr>
    <Son ref="son"></Son>
    <hr>
    <Dau></Dau>
  </div>
</template>

<script setup lang="ts">
//ref:可以获取真实的DOM节点,可以获取到子组件实例VC
//$parent:可以在子组件内部获取到父组件的实例
//引入子组件
import Son from './Son.vue'
import Dau from './Daughter.vue'
import {ref} from 'vue';
//父组件钱数
let money = ref(100000000);
//获取子组件的实例
let son = ref();
//父组件内部按钮点击回调
const handler = ()=>{
   money.value+=10;
   //儿子钱数减去10
   son.value.money-=10;
   son.value.fly();
}
//对外暴露
defineExpose({
   money
})
</script>

<style scoped>
.box{
  width: 100vw;
  height: 500px;
  background: skyblue;
}
</style>
<template>
  <div class="son">
    <h3>我是子组件:曹植{{money}}</h3>
  </div>
</template>

<script setup lang="ts">
import {ref} from 'vue';
//儿子钱数
let money = ref(666);
const fly = ()=>{
  console.log('我可以飞');
}
//组件内部数据对外关闭的,别人不能访问
//如果想让外部访问需要通过defineExpose方法对外暴露
defineExpose({
  money,
  fly
})
</script>

<style scoped>
.son {
  width: 300px;
  height: 200px;
  background: cyan;
}
</style>

父组件:要想子组件调用自己的方法和属性也必须进行暴露【 defineExpose({money}) 】

子组件:直接在方法里传参$parent,然后就可以调用父组件的属性和方法

<template>
  <div class="dau">
     <h1>我是闺女曹杰{{money}}</h1>
     <button @click="handler($parent)">点击我爸爸给我10000元</button>
  </div>
</template>

<script setup lang="ts">
import {ref} from 'vue';
//闺女钱数
let money = ref(999999);
//闺女按钮点击回调
const handler = ($parent)=>{
   money.value+=10000;
   $parent.money-=10000;
}
</script>

<style scoped>
.dau{
  width: 300px;
  height: 300px;
  background: hotpink;
}
</style>

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值