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、自定义事件
-
概述:自定义事件常用于:子 => 父。
-
注意区分好:原生事件、自定义事件。
-
原生事件:
- 事件名是特定的(
click
、mosueenter
等等) - 事件对象
$event
: 是包含事件相关信息的对象(pageX
、pageY
、target
、keyCode
)
- 事件名是特定的(
-
自定义事件:
- 事件名是任意名称
- 事件对象
$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>