《Vue3学习手记7》
组件通信(续)
$attrs
组件通信:$attrs 适用于祖传孙或孙传祖 (需要通过中间组件)
传递给后代的数据,但未被接收,都保存在attrs中
1.祖传孙
父组件:
<template><div class="father"><h3>父组件</h3><h3>a:{{ a }}</h3><h3>b:{{ b }}</h3><h3>c:{{ c }}</h3><Child :a="a" :b="b" :c="c"/> <!-- 1.1.传递给儿子 --></div>
</template><script setup lang="ts" name="Father">import Child from './Child.vue'import {ref} from 'vue'let a=ref(1)let b=ref(2)let c=ref(3)// 2.使用attrs实现孙传祖let gift=ref("")// 2.1 getGift函数function getGift(value:string){gift.value=value}// 使用mitt实现孙传祖// let gift=ref("")// emitter.on("getGift",(value:string)=>{// gift.value=value// })
</script>
子组件:
<template><div class="child"><h3>子组件</h3><GrandChild v-bind="$attrs"/> <!-- 1.2.儿子将父亲传递过来但未被接收的数据传给孙子 --></div>
</template><script setup lang="ts" name="Child">import GrandChild from './GrandChild.vue'
</script>
孙组件:
<template><div class="grand-child"><h3>孙组件</h3><h3>a:{{ a }}</h3><h3>b:{{ b }}</h3><h3>c:{{ c }}</h3></div>
</template><script setup lang="ts" name="GrandChild">
import {ref} from "vue"
const gift=ref("飞机")// 1.3 孙子接收数据defineProps(["a","b","c"]) //1.4 注意接收的内容
</script>
2.孙传祖
父组件:
<template><div class="father"><h3>父组件</h3><h3>a:{{ a }}</h3><h3>b:{{ b }}</h3><h3>c:{{ c }}</h3><Child :a="a" :b="b" :c="c" :getGift="getGift"/> <-- 2.2 将getGift函数传递过去--><hr><h2>得到孙子给的礼物:{{ gift }}</h2></div>
</template><script setup lang="ts" name="Father">import Child from './Child.vue'import {ref} from 'vue'let a=ref(1)let b=ref(2)let c=ref(3)// 2.使用attrs实现孙传祖let gift=ref("")// 2.1 getGift函数function getGift(value:string){gift.value=value}
</script>
子组件:
<template><div class="child"><h3>子组件</h3><GrandChild v-bind="$attrs"/> <!-- 1.2.儿子将父亲传递过来但未被接收的数据传给孙子 --></div>
</template>
孙组件:
<template><div class="grand-child"><h3>孙组件</h3><h3>a:{{ a }}</h3><h3>b:{{ b }}</h3><h3>c:{{ c }}</h3><hr><h4>礼物:{{gift}}</h4><button @click="getGift(gift)">点我将礼物给爷爷</button></div>
</template><script setup lang="ts" name="GrandChild">
import {ref} from "vue"
const gift=ref("飞机")// 1.3.孙子接收数据defineProps(["a","b","c","getGift"]) //1.4注意接收的内容
// 2.3使用attrs实现孙传祖--接收传递过来的函数getGift
</script>
$refs和 $parent
先使用ref进行通信:
父组件:
<template><!-- 组件通信:$refs父传子和$parents子传父 --><!-- 知识点1:ref --><div class="father"><h3>父组件</h3><h2>房子:{{ house }}栋</h2><h2>财产:{{ money }}万</h2><button @click="sendMoney">点击修改儿子1玩具为奥特曼</button><Child1 ref="ch1"/><Child2 ref="ch2"/></div>
</template><script setup lang="ts" name="Father">import Child1 from './Child1.vue'import Child2 from './Child2.vue'import { ref,reactive } from "vue";const house=ref(3)const money=ref(300)// 1.数据const ch1=ref()const ch2=ref()// 2.方法:function sendMoney(){ch1.value.toy="奥特曼"}
</script>
子组件:
<template><div class="child1"><h3>子组件1</h3><h2>书籍:{{ book }}本</h2><h2>玩具:{{toy}}</h2></div>
</template><script setup lang="ts" name="Child1">import { ref } from "vue";const book=ref(4)const toy=ref("乐高")// 3.defineExpose({toy}) //注意!里面是{},不是[]
</script>
$refs 父传子
父组件:
<template><!-- 组件通信:$refs父传子和$parents子传父 --><!-- 知识点1:ref --><div class="father"><h3>父组件</h3><h2>房子:{{ house }}栋</h2><h2>财产:{{ money }}万</h2><button @click="getAll($refs)">获取所有子组件的实例对象</button> <!-- 获取到所有打了ref标识的组件的实例对象 --><Child1 ref="ch1"/><Child2 ref="ch2"/></div>
</template><script setup lang="ts" name="Father">import Child1 from './Child1.vue'import Child2 from './Child2.vue'import { ref,reactive } from "vue";const house=ref(3)const money=ref(300)//***********************************************************************************
// 知识点二:当有很多子组件都需要修改,那就要写很多代码,可以使用$refs获得所有组件实例对象// $refsfunction getAll(refs:object){// console.log(refs)// 将child1和2的书籍增加两本// 遍历 (遍历数组用index索引值,遍历对象用key)for (let key in refs){// console.log(key) //输出ch1和ch2// console.log(refs[key])refs[key].book+=2}}
</script>
子组件:
//子组件1:
defineExpose({toy,book})
//子组件2:
defineExpose({book})
$parent 子传父
子组件:
<template>
<!-- 知识点三:子传父$parent --><button @click="reduceMoney($parent)">点我父亲资产减10万</button>
</template><script setup lang="ts" name="Child1">import { ref } from "vue";const book=ref(4)const toy=ref("乐高")// ***********************************3.1 function reduceMoney(parent:any){ //"parent"自己定义// console.log(parent) //得到的就是父组件defineExpose的数据parent.money-=10}
</script>
父组件:
// 3.2 defineExpose({money})
provide和inject
组件通信:provide和inject祖孙通信。
和attrs区别在于:不用使用中间组件而attrs需要使用中间组件
祖组件:
祖——孙
<template>组件通信:provide和inject祖孙通信。和attrs区别在于:不用使用中间组件而attrs需要使用中间组件 <div class="father"><h3>父组件</h3><h2>房子:{{ house }}栋</h2><h2>财产:{{ money }}万</h2><Child/></div>
</template><script setup lang="ts" name="Father">import Child from './Child.vue'import {ref,reactive,provide,inject} from 'vue'const house=ref(3)const money=ref(300)// 1.2 爷爷传递数据给孙子provide("money",money) //第一个money可自定义
</script>
孙组件:
<template><div class="grand-child"><h3>我是孙组件</h3><h2>书籍:{{ book }}本</h2><h2>玩具:{{toy}}</h2><h2>得到爷爷的money:{{ money }}万</h2></div>
</template><script setup lang="ts" name="GrandChild">import {ref} from "vue"import {provide,inject} from "vue"const book=ref(4)const toy=ref("乐高")// *****************************************************// 知识点一:祖-孙,实现爷爷向孙子通信(传递数据)// 1.1 得到爷爷传过来的数据let money=inject("money",0)//第二个参数是默认值
</script>
孙——祖
祖组件:
// 2.1定义一个函数function changeMoney(value:number){money.value-=value}// 2.2提供changeMoney函数provide("moneyText",{money,changeMoney}) //提供多个内容用对象形式
孙组件:
<button @click="changeMoney(2)">点我修改爷爷的money</button>// 知识点二:孙-祖,实现孙子向爷爷通信(传递数据)// 2.3注入let {money,changeMoney}=inject("moneyText",0)
pinia
可以参考前边对pinia的理解
slot插槽
组件通信:slot-父组件向子组件传递模板内容
默认插槽
数据在父组件
父组件:
<template><div class="father"><Category title="今日游戏推荐"><ul><li v-for="(g,id) in games" :key="id">{{ g.name }}</li></ul></Category><Category title="今日美食推荐"><img :src="img" alt=""></Category><Category title="今日视频推荐"><video :src="video"></video></Category></div>
</template><script setup lang="ts" name="Father">
import Category from './Category.vue';
import {ref,reactive} from 'vue'
let games = reactive([{id:'asgytdfats01',name:'英雄联盟'},{id:'asgytdfats02',name:'王者农药'},{id:'asgytdfats03',name:'红色警戒'},{id:'asgytdfats04',name:'斗罗大陆'}])const img=ref("https://z1.ax1x.com/2023/11/19/piNxLo4.jpg")const video=ref("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
</script>
子组件:
<template><div class="game"><h2>{{title}}</h2><slot>如果没有内容展示就显示默认内容</slot><!-- 等同于: --><!-- <slot name="default"></slot> --></div>
</template><script setup lang="ts" name="Game">
defineProps(["title"])
</script>
具名插槽
数据在父组件
父组件:
实现h2标题在内容下——一般用于内容展示和模板中的顺序不一样,使用template标签
<template><div class="father"><Category><template v-slot:two> <!-- 注意!这里不是= --><h2>今日游戏推荐</h2></template><template v-slot:one><ul><li v-for="(g,id) in games" :key="id">{{ g.name }}</li></ul></template></Category><Category><template #two> <!-- 简写 --><h2>今日美食推荐</h2></template><template #one> <img :src="img" alt=""></template></Category><Category><template v-slot:two> <h2>今日视频推荐</h2></template><template v-slot:one> <video :src="video"></video></template></Category></div>
</template><script setup lang="ts" name="Father">
import Category from './Category.vue';
import {ref,reactive} from 'vue'
let games = reactive([{id:'asgytdfats01',name:'英雄联盟'},{id:'asgytdfats02',name:'王者农药'},{id:'asgytdfats03',name:'红色警戒'},{id:'asgytdfats04',name:'斗罗大陆'}])const img=ref("https://z1.ax1x.com/2023/11/19/piNxLo4.jpg")const video=ref('http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4')
</script>
子组件:
<template><div class="game"><h2>{{title}}</h2><slot name="one">如果没有内容展示就显示默认内容</slot><slot name="two"></slot></div>
</template><script setup lang="ts">
defineProps(["title"])</script>
作用域插槽
父组件:
数据在子组件
<template><!-- 作用域插槽 --><div class="father"><Category><template v-slot:two> <!-- 注意!这里不是= --><h2>今日游戏推荐</h2></template><template v-slot:one="params"><ul><li v-for="(g,id) in params.games" :key="id">{{ g.name }}</li></ul></template></Category><Category><template #two> <!-- 简写 --><h2>今日美食推荐</h2></template><template #one="params"> <img :src="params.image" alt=""></template></Category><Category><template v-slot:two> <h2>今日视频推荐</h2></template><template v-slot:one="params"> <video :src="params.video"></video></template></Category></div>
</template><script setup lang="ts" name="Father">
import Category from './Category.vue';
</script>
子组件:
<template><div class="game"><h2>{{title}}</h2><slot name="one" :games="games" :image="img" :video="video">如果没有内容展示就显示默认内容</slot><slot name="two"></slot></div>
</template><script setup lang="ts">
defineProps(["title"])
import {ref,reactive} from 'vue'
let games = reactive([{id:'asgytdfats01',name:'英雄联盟'},{id:'asgytdfats02',name:'王者农药'},{id:'asgytdfats03',name:'红色警戒'},{id:'asgytdfats04',name:'斗罗大陆'}])const img=ref("https://z1.ax1x.com/2023/11/19/piNxLo4.jpg")const video=ref('http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4')
</script>