组件通信(续)
$attrs
组件通信:$attrs 适用于祖传孙 或孙传祖 (需要通过中间组件)
传递给后代的数据,但未被接收,都保存在attrs中
1.祖传孙
父组件:
clike
<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>
子组件:
clike
<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>
孙组件:
clike
<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.孙传祖
父组件:
clike
<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>
子组件:
clike
<template>
<div class="child">
<h3>子组件</h3>
<GrandChild v-bind="$attrs"/> <!-- 1.2.儿子将父亲传递过来但未被接收的数据传给孙子 -->
</div>
</template>
孙组件:
clike
<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进行通信:
父组件:
clike
<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>
子组件:
clike
<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 父传子
父组件:
clike
<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获得所有组件实例对象
// $refs
function 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>
子组件:
clike
//子组件1:
defineExpose({toy,book})
//子组件2:
defineExpose({book})
$parent 子传父
子组件:
clike
<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>
父组件:
clike
// 3.2
defineExpose({money})
provide和inject
组件通信:provide和inject祖孙通信。
和attrs区别在于:不用使用中间组件而attrs需要使用中间组件
祖组件:
祖------孙
clike
<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>
孙组件:
clike
<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>
孙------祖
祖组件:
clike
// 2.1定义一个函数
function changeMoney(value:number){
money.value-=value
}
// 2.2提供changeMoney函数
provide("moneyText",{money,changeMoney}) //提供多个内容用对象形式
孙组件:
clike
<button @click="changeMoney(2)">点我修改爷爷的money</button>
// 知识点二:孙-祖,实现孙子向爷爷通信(传递数据)
// 2.3注入
let {money,changeMoney}=inject("moneyText",0)
pinia
可以参考前边对pinia的理解
slot插槽
组件通信:slot-父组件向子组件传递模板内容
默认插槽
数据在父组件
父组件:
clike
<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>
子组件:
clike
<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标签
clike
<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>
子组件:
clike
<template>
<div class="game">
<h2>{{title}}</h2>
<slot name="one">如果没有内容展示就显示默认内容</slot>
<slot name="two"></slot>
</div>
</template>
<script setup lang="ts">
defineProps(["title"])
</script>
作用域插槽
父组件:
数据在子组件
clike
<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>
子组件:
clike
<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>