19、vue3组件通信

1、props

常见搭配形式

概述:props是使用频率最高的一种通信方式,常用与 :父 ↔ 子

  • 父传子:属性值是非函数
  • 子传父:属性值是函数

Father.vue

<template>
  <div>
    <h1>父亲</h1>
    <h1>父亲有遗产:【{{ moeny }}】元,要传给儿子</h1>
    <h3>父亲收到儿子送的手机:{{ erziPhone }}</h3>
    <h1>--------------------------</h1>
    <Son :father="moeny" :getIphone="getIphone"/>
  </div>
</template>

<script setup lang="ts" name="Father">
import Son from './Son.vue';
import { ref } from 'vue';
let moeny=ref(1000)
let erziPhone=ref()

function getIphone(value:string){
  erziPhone.value=value

}
 
</script>

<style scoped>

</style>

Son.vue

<template>
  <div>
   <h1>儿子</h1>
   <h1>儿子要送父亲一部【{{ iphone }}】手机</h1>
   <h3>继承父亲的遗产:{{ father }}</h3>
   <button @click="getIphone(iphone)">送给父亲手机</button>
  </div>
</template>

<script setup lang="ts" name="Son">
import { ref } from 'vue';
let iphone=ref('苹果')
 
 defineProps(['father','getIphone'])
</script>

<style scoped>

</style>

2、自定义事件

  1. 概述:自定义事件常用于:子 => 父。

  2. 注意区分好:原生事件、自定义事件。

  • 原生事件:

    • 事件名是特定的(clickmosueenter等等)
    • 事件对象$event: 是包含事件相关信息的对象(pageXpageYtargetkeyCode
  • 自定义事件:

    • 事件名是任意名称
    • 事件对象$event: 是调用emit时所提供的数据,可以是任意类型!!!

Father.vue

<template>
  <div>
    <h1>父亲</h1>
    <h1>父亲有遗产:【{{ moeny }}】元,要传给儿子</h1>
    <h3>父亲收到儿子送的手机:{{ erziPhone }}</h3>
    <h1>--------------------------</h1>
    <!-- 给子组件绑定自定义事件 -->
    <Son :father="moeny" @get-iphone="Iphone"/>
  </div>
</template>

<script setup lang="ts" name="Father">
import Son from './Son.vue';
import { ref } from 'vue';
let moeny=ref(1000)
let erziPhone=ref('')

function Iphone(value:string){
  console.log('value',value)
  erziPhone.value=value

}
 
</script>

<style scoped>

</style>

Son.vue

<template>
  <div>
   <h1>儿子</h1>
   <h1>儿子要送父亲一部【{{ iphone }}】手机</h1>
   <h3>继承父亲的遗产:{{ father }}</h3>
   <button @click="emit('get-iphone',iphone)">送给父亲手机</button>
  </div>
</template>

<script setup lang="ts" name="Son">
import { ref } from 'vue';
let iphone=ref('苹果')
 
 defineProps(['father'])
//  声明事件
const emit=defineEmits(['get-iphone'])
</script>

<style scoped>

</style>

3、mitt

mitt可以实现任意组件间通信

mitter.ts

import mitt from "mitt";

const emitter=mitt()

export default emitter

Son.vue

<template>
  <div>
   <h1>儿子</h1>
   <h1>儿子要送父亲一部【{{ iphone }}】手机</h1>
   <button @click="songIphone">送给父亲手机</button>
  </div>
</template>

<script setup lang="ts" name="Son">
import { ref } from 'vue';
import emitter from '@/utils/mitter';
let iphone=ref('苹果')
 
function songIphone(){
  emitter.emit('faIphone',iphone)

}
</script>

<style scoped>

</style>

Father.vue

<template>
  <div>
    <h1>父亲</h1>
    <h3>父亲收到儿子送的手机:{{ erziPhone }}</h3>
    <h1>--------------------------</h1>
    <!-- 给子组件绑定自定义事件 -->
    <Son/>
  </div>
</template>

<script setup lang="ts" name="Father">
import emitter from '@/utils/mitter';
import { onUnmounted } from 'vue';
import Son from './Son.vue';
import { ref } from 'vue';

let erziPhone=ref('')

emitter.on('faIphone',(value:any)=>{
  erziPhone.value=value
})

onUnmounted(()=>{
  // 解绑事件
  emitter.off('faIphone')
})
 
</script>

<style scoped>

</style>

4、v-model

双向绑定,实现 父↔子 之间相互通信。这种方式用的少。

5、$attrs

  • 概述:$attrs用于实现当前组件的父组件,向当前组件的子组件通信(祖→孙)。

  • 具体说明:$attrs是一个对象,包含所有父组件传入的标签属性。

    注意:$attrs会自动排除props中声明的属性(可以认为声明过的 props 被子组件自己“消费”了)

 YeYe.vue

<template>
  <div>
   <h1>爷爷</h1>
   <h1>爷爷要送给孙子礼物</h1>
  <h3>礼物1:{{ gift1 }}</h3>
  <h3>礼物2:{{ gift2 }}</h3>
  <h3>爷爷收到孙子送来的【{{ sun }}】,非常的开心</h3>
  <h1>--------------------------</h1>
  <Father :gift1="gift1" :gift2="gift2" v-bind="{house:'别墅',car:'宝马'}" :getLift="getLift"/>
  
  </div>
</template>

<script setup lang="ts" name="YeYe">
import { ref } from 'vue';
import Father from './Father.vue';

let gift1=ref('100万')
let gift2=ref('美女')

let sun=ref('')
 
function getLift(value){
  sun.value=value
}

</script>

<style scoped>

</style>

Father.vue

<template>
  <div>
    <h1>父亲</h1>
    <h1>--------------------------</h1>
    <SunZi v-bind="$attrs"/>
  </div>
</template>

<script setup lang="ts" name="Father">
import SunZi from './SunZi.vue';
import { ref } from 'vue';



 
</script>

<style scoped>

</style>

SunZi.vue

<template>
  <div>
   <h1>孙子</h1>
   <h1>孙子收到爷爷送来的礼物{{ $attrs }}</h1>

   <button @click="getLift('奶茶')">孙子为了感谢爷爷,送给爷爷一杯奶茶</button>
  
  </div>
</template>

<script setup lang="ts" name="SunZi">
import { ref } from 'vue';

defineProps(['getLift'])
 

</script>

<style scoped>

</style>

6、refs、parent

  • 概述:

    • $refs用于 :父→子。
    • $parent用于:子→父。
  • 原理如下:

    属性说明
    $refs值为对象,包含所有被ref属性标识的DOM元素或组件实例。
    $parent值为对象,当前组件的父组件实例对象。

 Father.vue

<template>
  <div>
    <h1>父亲</h1>
    <h3>父亲有遗产:【{{ money }}】RMB</h3>
    <button @click="upCar">修改孩子1的奔驰</button>
    <button @click="findGirl">给孩子2找个好的女朋友</button>

    <button @click="getAll($refs)">同时给孩子买零食吃</button>

    <h3>--------------</h3>

    <ErZi1 ref="c1"/>
    <ErZi2 ref="c2"/>
  </div>
</template>

<script setup lang="ts" name="Father">
import ErZi1 from './ErZi1.vue';
import ErZi2 from './ErZi2.vue';
import { ref } from 'vue';
let money=ref(100000)
let c1=ref()
let c2=ref()


function upCar(){
  c1.value.car='大众'

}

function findGirl(){
  c2.value.girl='贤惠的妻子'
}

function getAll(refs:any){
  for (let key in refs){
    refs[key].latiao+=2

  }

}

defineExpose({money})
 
</script>

<style scoped>

</style>

ErZi1.vue

<template>
  <div>
   <h1>儿子1</h1>
  <h3>儿子1有一辆【{{ car }}】</h3>
  <h3>儿子1有辣条【{{ latiao }}】包</h3>
  <button @click="jiche($parent)">儿子1继承父亲的遗产:10000</button>
  <h3>--------------</h3>
  </div>
</template>

<script setup lang="ts" name="ErZi1">
import { ref } from 'vue';
let car=ref('奔驰')
let latiao=ref(2)

 function jiche(parent:any){
  parent.money-=10000

 }
defineExpose({car,latiao})

</script>

<style scoped>

</style>

ErZi2.vue

<template>
  <div>
   <h1>儿子2</h1>
  <h3>儿子2有一个【{{ girl }}】女友</h3>
  <h3>儿子2有辣条【{{ latiao }}】包</h3>
  <button @click="jiche2($parent)">儿子2继承父亲的遗产:1</button>
  
  </div>
</template>

<script setup lang="ts" name="ErZi12">
import { ref } from 'vue';
let girl=ref('绿茶')
let latiao=ref(10)
 
function jiche2(parent:any){
  parent.money-=1
}

defineExpose({girl,latiao})
</script>

<style scoped>

</style>

7、provide、inject

  • 概述:实现祖孙组件直接通信

  • 具体使用:

    • 在祖先组件中通过provide配置向后代组件提供数据
    • 在后代组件中通过inject配置来声明接收数据

 YeYe.vue

<template>
  <div>
   <h1>爷爷</h1>
  <h3>爷爷有遗产【{{money}}】万</h3>
  <h3>爷爷有【{{info.car}}】,还有【{{info.house}}】</h3>
  <h3>------------</h3>
  <Father/>
  </div>
</template>

<script setup lang="ts" name="YeYe">
import { ref,reactive, provide } from 'vue';
import Father from './Father.vue';
let money=ref(100)
const info=reactive({
  car:'奔驰',
  house:'大别野'
})

function jicheMoner(value:number){
  money.value-=value
}
 provide('info',info)
 provide('context',{money,jicheMoner})
</script>

<style scoped>

</style>

Father.vue

<template>
  <div>
    <h1>父亲</h1>
    <h3>-----------</h3>
    <SunZi/>
    
  </div>
</template>

<script setup lang="ts" name="Father">

import SunZi from './SunZi.vue';



 
</script>

<style scoped>

</style>

SunZi.vue

<template>
  <div>
   <h1>孙子</h1>
   <h3>孙子继承爷爷的【{{ info.car }}】,以及大【{{ info.house }}】</h3>
   <button @click="jicheMoner(1)">继承爷爷的钱</button>
  </div>
</template>

<script setup lang="ts" name="SunZi">
import { inject } from 'vue';

const info=inject('info',{car:String,house:String})

let {money,jicheMoner}=inject('context',{money:0,jicheMoner:(param:number)=>{}})
</script>

<style scoped>

</style>

8、slot插槽

默认插槽

Father.vue

<template>
  <div>
    <h1>父亲</h1>
    <kind>
      <h1>吃</h1>
      <ul>
        <li>重庆火锅</li>
        <li>川菜</li>
        <li>小炒黄牛肉</li>
      </ul>
    </kind>
    <kind>
      <h1>喝</h1>
      <ul>
        <li>哇哈哈</li>
        <li>矿泉水</li>
      </ul>
    </kind>
    
    
  </div>
</template>

<script setup lang="ts" name="Father">

import kind from './kind.vue';



 
</script>

<style scoped>

</style>

Kind.vue

<template>
  <div>
    <slot>默认槽位</slot>
  <Father/>
  </div>
</template>

<script setup lang="ts" name="Kind">
import { ref,reactive } from 'vue';

</script>

<style scoped>

</style>

具名插槽

Father.vue

<template>
  <div>
    <h1>父亲</h1>
    <kind>
      <template v-slot:one>
        <h1>吃</h1>
        <ul>
          <li>重庆火锅</li>
          <li>川菜</li>
          <li>小炒黄牛肉</li>
        </ul>
      </template>
    </kind>
   <kind>
    <template #two>
      <h1>喝</h1>
      <ul>
        <li>哇哈哈</li>
        <li>矿泉水</li>
      </ul>
    </template>
  </kind>
    
    
  </div>
</template>

<script setup lang="ts" name="Father">

import kind from './kind.vue';



 
</script>

<style scoped>

</style>

Kind.vue

<template>
  <div>
    <slot name="one"></slot>
    <slot name="two"></slot>
  <Father/>
  </div>
</template>

<script setup lang="ts" name="Kind">
import { ref,reactive } from 'vue';

</script>

<style scoped>

</style>

作用域插槽

Father.vue

<template>
  <div>
    <h1>父亲</h1>
    <kind v-slot="params">
      <ul>
        <li v-for="g in params.girl" :key="g.id">{{ g.name }}</li>
      </ul>
    </kind>
    
  </div>
</template>

<script setup lang="ts" name="Father">

import kind from './kind.vue';



 
</script>

<style scoped>

</style>

Kind.vue

<template>
  <div>
    <slot :girl="girl" a="哦哦"></slot>
   
  <Father/>
  </div>
</template>

<script setup lang="ts" name="Kind">
import { ref,reactive } from 'vue';
let girl = reactive([
          {id:'01',name:'貂蝉'},
          {id:'02',name:'西施'},
          {id:'03',name:'王昭君'}
        ])

</script>

<style scoped>

</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尘缘浮梦

你的鼓励将是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值