《Vue3学习手记7》

组件通信(续)

$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>
相关推荐
若愚67923 分钟前
Tauri 跨平台开发指南及实战:用前端技术征服桌面应用(合集-万字长文)
前端·vue.js·rust·gitcode
不秃的开发媛16 分钟前
前端技术Ajax实战
前端·javascript·ajax
liang899927 分钟前
Shiro学习(七):总结Shiro 与Redis 整合过程中的2个问题及解决方案
redis·学习·bootstrap
weixin_4862814535 分钟前
FFmpeg源码学习---ffmpeg
学习·ffmpeg
qq_419429131 小时前
uni-app中使用RenderJs 使用原生js
前端·javascript·uni-app
沃野_juededa1 小时前
uniapp自定义选项卡
java·前端·javascript
爱笑的眼睛111 小时前
React Navigation 使用指南
javascript·react native·react.js
刺客-Andy1 小时前
React 第三十五节 Router 中useNavigate 的作用及用途详解
前端·javascript·react.js·前端框架
沙尘暴炒饭1 小时前
解决vue3 路由query传参刷新后数据丢失的问题
开发语言·前端·javascript
chengRantianxia1 小时前
UNIAPP项目记录
前端·vue.js·uni-app