首页 > 其他分享 >前端学习-vue视频学习014-组件通信

前端学习-vue视频学习014-组件通信

时间:2024-04-10 22:01:14浏览次数:17  
标签:vue parent 学习 toy 014 child import ref

尚硅谷视频教程

通信方式1 props

parent传child--只能传递非函数

// Parent.vue
<template>
    <div class="parent">
        <h3>parent</h3>
		<h3>car: {{ car }}</h3>
		<Child :car="car"/>
    </div>
</template>

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

	let car = ref('a car')
</script>
Child.vue
<template>
    <div class="child">
        <h3>child</h3>
		<h3>car from parent: {{ car }}</h3>
    </div>
</template>

<script setup>
	import { ref } from 'vue';
	import { defineProps } from 'vue';
	defineProps(['car'])
</script>

child传parent--只能由parent传给child函数,child调用函数将数据给parent

// Parent.vue
<template>
    <div class="parent">
        <h3>parent</h3>
		<h3>car: {{ car }}</h3>
		<h3 v-show="toy">{{ toy }}</h3>
		<Child :car="car" :sendToy="getToy"/>
    </div>
</template>

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

	let car = ref('a car')
	let toy = ref('')
	function getToy(val) {
		toy.value = val
	}
</script>
// Child.vue
<template>
    <div class="child">
        <h3>child</h3>
		<h3>car from parent: {{ car }}</h3>
		<button @click="sendToy(toy)">sendToy</button>
    </div>
</template>

<script setup>
	import { ref } from 'vue';
	import { defineProps } from 'vue';
	defineProps(['car','sendToy'])

	let toy = ref('a bear')
</script>

通信方式2 自定义事件 event

  • 只用于child传给parent
  • $event用于接收点击事件
  • 事件名由多个单词组成时,使用类似send-toy的写法
  • const emit = defineEmits(['send-toy'])是规范写法
// Parent.vue
<template>
    <div class="parent">
        <h3>parent</h3>
		<h3 v-show="toy">{{ toy }}</h3>
		<Child @send-toy="getToy"/>
    </div>
</template>

<script setup lang="ts">
	import Child from './Child.vue';
	import { ref } from 'vue';
	let toy = ref('')

	function getToy(val) {
		toy.value = val
	}
</script>
// Child.vue
<template>
    <div class="child">
        <h3>child</h3>
		<button @click="emit('send-toy',toy)">send-toy</button>
    </div>
</template>

<script setup>
	import { ref } from 'vue';
	let toy = ref('a kind toy')

	const emit = defineEmits(['send-toy'])
</script>

通信方式3 mitt 实现任意组件之间数据互传

引入mitt

  • npm i mitt
  • 新建tools或utils文件夹,新建emitter.ts文档,用于引入mitt
import mitt from 'mitt'
// emitter可以绑定事件、触发事件
const emitter = mitt()
export default emitter

如何使用mitt

// 绑定事件
emitter.on('useMitt1',()=>{
    console.log('useMitt1');
})
emitter.on('useMitt2',()=>{
    console.log('useMitt2');
})

// 调用事件
setInterval(()=>{
    emitter.emit('useMitt1')
    emitter.emit('useMitt2')
},1000)

// 移除事件
setTimeout(()=>{
    // emitter.off('useMitt1')
    emitter.all.clear()
},3000)

使用mitt在两个组件间传递数据

接收数据的组件:绑定事件
传输数据的组件:触发事件

下例:child2传数据给child1

// Child1.vue
<template>
    <div class="child">
        <h3>child</h3>
		<h3 v-show="toy">{{ toy }}</h3>
    </div>
</template>

<script setup>
	import { ref } from 'vue';
	import emitter from '@/utils/emitter';
	let toy = ref('')

	emitter.on('send-toy',(val)=>{
		toy.value = val
	})
</script>
// Child2.vue
<template>
    <div class="child">
        <h3>child</h3>
		<h3>child2's toy {{ toy }}</h3>
		<button @click="emitter.emit('send-toy',toy)">send-toy</button>
    </div>
</template>

<script setup>
	import { ref } from 'vue';
	import emitter from '@/utils/emitter';
	
	let toy = ref('a toy')
</script>

注意事项:最好在绑定事件后增加:当组件卸载时,解绑事件

	emitter.on('send-toy',(val)=>{
		toy.value = val
	})

	onUnmounted(()=>{
		emitter.off('send-toy')
	})

通信方式4 v-model

HTML标签使用v-model

// 直接使用v-model
<input type="text" v-model="username">
// v-model实现的底层逻辑
<input type="text" :value="username" @input="username = (<HTMLInputElement>$event.target).value">

组件标签使用v-model

<TestUIInput v-model="username"/>
// 底层逻辑
<TestUIInput :modelValue="username" @update:modelValue="username = $event"/>

组件标签可以使用v-model的前提是已经封装好了对应的逻辑

// TestUIInput.vue
<template>
    <input type="text" :value="modelValue" @input="emit('update:modelValue',(<HTMLInputElement>$event.target).value)">
</template>

<script setup lang="ts" name="TestUIInput">
	import { ref } from 'vue';
    defineProps(['modelValue'])
    const emit = defineEmits(['update:modelValue'])
</script>

关于$event

对于原生事件,要使用$event.target
对于自定义事件,$event是触发事件时传递的数据

更换v-model(类似于命名?),可以使用多个v-model

<TestUIInput v-model:uName="username" v-model:pwd="password"/>
// TestUIInput.vue
<template>
    <input type="text" :value="uName" @input="emit('update:uName',(<HTMLInputElement>$event.target).value)">
    <input type="text" :value="pwd" @input="emit('update:pwd',(<HTMLInputElement>$event.target).value)">
</template>

<script setup lang="ts" name="TestUIInput">
	import { ref } from 'vue';
    defineProps(['uName','pwd'])
    const emit = defineEmits(['update:uName','update:pwd'])
</script>

通信方式5 attrs 实现祖辈传递孙辈

  • 祖辈准备数据并传给child
<template>
    <div class="parent">
        <h3>parent</h3>
		<Child :a="a" :b="b" :c="c" v-bind="{x:100,y:300}" :changeA="changeA"/>
    </div>
</template>
  • child不接收任何数据,并使用$attrs将数据传给grandchild
<template>
    <div class="child">
        <h3>child</h3>
		<Grandchild v-bind="$attrs"/>
    </div>
</template>

<script setup name="Child">
	import Grandchild from './Grandchild.vue';
	defineProps([''])
</script>
  • grandchild接收所有数据
<template>
    <div class="child">
        <h3>Grandchild</h3>
		<h4>{{ a }}</h4>
		<h4>{{ b }}</h4>
		<h4>{{ c }}</h4>
		<h4>{{ x }}</h4>
		<h4>{{ y }}</h4>
		<button @click="changeA(b)">changeA</button>
    </div>
</template>

<script setup name="Grandchild">
	defineProps(['a','b','c','x','y','changeA'])
</script>

通信方式6 $refs 实现parent影响child $parent 实现child影响parent

使用ref,parent修改单个child的数据

Parent.vue

<template>
    <div class="parent">
        <h3>parent</h3>
		<button @click="changeToy">change toy</button>
		<Child1 ref="c1"/>
		
    </div>
</template>

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

	let c1 = ref()

	function changeToy(){
		c1.value.toy = 'another toy'
	}

</script>

Child.vue

<template>
    <div class="child">
        <h3>child</h3>
		<h3>{{ toy }}</h3>
    </div>
</template>

<script setup>
	import { onUnmounted, ref } from 'vue';
	let toy = ref('toytoy')
	let book = ref(6)

	defineExpose({toy,book})

使用$refs,parent修改多个child的数据

Parent.vue

<template>
    <div class="parent">
        <h3>parent</h3>
		<button @click="addBook($refs)">add book</button>
		<Child1 ref="c1"/>
		<Child2 ref="c2"/>
    </div>
</template>

<script setup lang="ts">
	import Child1 from './Child1.vue';
	import Child2 from './Child2.vue';
	import { ref } from 'vue';

	let c1 = ref()
	let c2 = ref()

	function addBook(refs){
		for (const key in refs) {
			refs[key].book += 4
		}
	}

</script>

Child1.vue

<template>
    <div class="child">
		<h3>{{ book }}</h3>
    </div>
</template>

<script setup>
	import { onUnmounted, ref } from 'vue';
	let book = ref(9)

	defineExpose({book})

</script>

Child2.vue

<template>
    <div class="child">
		<h3>{{ book }}</h3>
    </div>
</template>

<script setup>
	import { onUnmounted, ref } from 'vue';
	let book = ref(9)

	defineExpose({book})

</script>

使用$parent,child修改parent的数据

Parent.vue

<template>
    <div class="parent">
        <h3>parent</h3>
		<h3>house {{ house }}</h3>
		<Child1 ref="c1"/>
		<Child2 ref="c2"/>
		
    </div>
</template>

<script setup lang="ts">
	import Child1 from './Child1.vue';
	import Child2 from './Child2.vue';
	import { ref } from 'vue';

	let house = ref(5)

	defineExpose({house})

</script>

Child.vue

<template>
    <div class="child">
        <h3>child</h3>
		<button @click="minusHouse($parent)">minusHouse</button>
    </div>
</template>

<script setup>
	function minusHouse(parent){
		parent.house -= 1
	}

</script>

通信方式7 provide inject 实现parent和所有后代之间的通信

Parent.vue

<template>
    <div class="parent">
        <h3>parent</h3>
		<h3>money {{ money }}</h3>
		<ChildOrGrandchild/>
    </div>
</template>

<script setup lang="ts">
	import ChildOrGrandchild from './ChildOrGrandchild.vue';
	import { provide, ref } from 'vue';

	let money = ref(20000)
	function changeMoney(val){
		money.value -= val
	}

	provide('moneyContext',{money,changeMoney})
</script>

ChildOrGrandchild.vue

<template>
    <div class="child">
        <h3>ChildOrGrandchild</h3>
		<h3>money: {{ money }}</h3>
		<button @click="changeMoney(8)">changeMoney</button>
    </div>
</template>

<script setup name="Child">
	import { inject } from 'vue'
	let {money,changeMoney} = inject('moneyContext','default')
</script>

通信方式8 pinia 参考此链接

通信方式9 slot

默认插槽

在组件标签内填写想要插入的元素即可

// Parent.vue
<template>
    <div class="parent">
        <h3>parent</h3>
		
		<div class="d-flex justify-content-around">
			<Child title="标题1">
				<ul>
					<li v-for="item in list" :id="item.id">{{ item.name }}</li>
				</ul>
			</Child>
			<Child title="标题2">
				<img :src="imgUrl" alt="">
			</Child>
			<Child title="标题3">
				<video :src="videoUrl" controls></video>
			</Child>
		</div>
    </div>
</template>
// Child.vue
<template>
    <div class="child">
        <h5 class="bg-primary text-light">{{ title }}</h5>
		<slot>default</slot>
    </div>
</template>

具名插槽

  • slot标签增加name属性命名
  • v-slot:name 只能用在组件标签或者template标签
// Parent.vue
<template>
    <div class="parent">
        <h3>parent</h3>
		
		<div class="d-flex justify-content-around">
			<Child v-slot:s2>
				<h5 class="bg-primary text-light">标题1</h5>
				<ul>
					<li v-for="item in list" :id="item.id">{{ item.name }}</li>
				</ul>
			</Child>
			<Child>
				<template v-slot:s1>
					<h5 class="bg-primary text-light">标题2</h5>
				</template>
				<template v-slot:s2>
					<img :src="imgUrl" alt="">
				</template>
			</Child>
			<Child v-slot:s1 title="标题3">
				<video :src="videoUrl" controls></video>
			</Child>
		</div>
    </div>
</template>
// Child.vue
<template>
    <div class="child">
        
		<slot name="s1">default1</slot>
		<slot name="s2">default2</slot>
    </div>
</template>

作用域插槽

  • 数据在child组件
  • 使用数据的结构在parent组件
  • child组件在使用slot的时候将数据传出去
// Child.vue
 <template>
    <div class="child">
        
		<slot name="s1" :games="games" x="aaa" y="bbb"></slot>
		<slot :games="games"></slot>
    </div>
</template>

<script setup name="Child">
	import { reactive } from 'vue';

	let games = reactive([
		{name:'game1',id:'lll01'},
		{name:'game2',id:'lll02'},
		{name:'game3',id:'lll03'},
		{name:'game4',id:'lll04'},
	])

</script>
// Parent.vue
<template>
    <div class="parent">
        <h3>parent</h3>
		
		<div class="d-flex justify-content-around">
			<Child v-slot:s1="params">
				<h5 class="bg-primary text-light">{{ params }}</h5>
			</Child>
			<Child v-slot="params">
				<ol>
					<li v-for="item in params.games" :id="item.id">{{ item.name }}</li>
				</ol>
			</Child>
			<Child v-slot:s1="params" title="标题3">
				<h2 v-for="item in params.games" :id="item.id">{{ item.name }}</h2>
			</Child>
		</div>
    </div>
</template>

<script setup lang="ts">
	import Child from './Child.vue';
</script>

标签:vue,parent,学习,toy,014,child,import,ref
From: https://www.cnblogs.com/ayubene/p/18097551

相关文章

  • 【学习笔记】线段树(待补)
    零、写在前面的话我发现学习笔记是真的有必要的。很多比赛甚至做题的时候,学过的算法就出现在题目里面,然而我却忘记了之前对这个算法的深入理解,甚至忘了这个算法怎么打,更甚者,看不出来这个题目可以使用这种算法解决。为了防止这种情况再度出现,我决定对自己的任何学过的算法写笔记,......
  • 【学习笔记】树链剖分
    一、重链剖分1.定义&作用树链剖分用于解决在树上执行的操作,将树上操作变为区间操作。用区间来维护。2.主要思想&实现有一棵树然后,我们把边区分一下,有一些边是“重边”,其余的是“轻边”,像这样:(红边为重边,黑边为轻)重边和轻边如何确定呢?看每一个结点旁的红色数字,代表他......
  • 【学习笔记】好题
    常来看看。Antiluna好闪,拜谢Antiluna。1.奖金每位参加会谈的代表提出了自己的意见:“我认为员工a的奖金应该比b高!”Mr.Z决定要找出一种奖金方案,满足各位代表的意见,且同时使得总奖金数最少。每位员工奖金最少为100元,且必须是整数。1≤n≤10000,1≤m≤20000。......
  • 【学习笔记】dijkstra
    一、dijkstra1.定义&作用很简单。一个单源最短路算法。2.思想&实现我觉得sm的图已经够了。二、堆优化dijkstra1.先来认识一下proirity_queue2.如何使用proirity_queue对dijkstra优化?每一步,我们都需要找到\(d\)值最小的节点(即\(......
  • 【学习笔记】spfa
    一、spfa模板:voidspfa(intx){ for(inti=1;i<=n;i++) vis[i]=0,dis[i]=inf; dis[1]=0,f[1]=1; q.push(1); while(!q.empty()) { intt=q.front(); q.pop(); vis[t]=0; for(inti=first[t];i;i=e[i].next) { intto=e[i].to; if(dis[t]+e[i].v<......
  • 前端开发之el-table(vue2中)固定列fixed滚动条被固定列盖住
    固定列fixed滚动条被固定列盖住效果图前言解决方案效果图前言在使用fixed固定列的时候会出现滚动条被盖住的情况解决方案改变el-table固定列的计算高度即可.el-table{.el-table__fixed-right,.el-table__fixed{height:auto!important;......
  • 【学习笔记】并查集
    一、普通并查集1.定义&作用并查集是管理元素分组的算法,可以高效对元素分组(合并为一组)以及查询两个元素是否在一组。2.主要思想&实现对于每一个组,设置一个“组长”,每一次合并时只需要将其中一组的组长设为另一组的组长,查询时只需要查询组长是否相同。每一个组都可以理解......
  • Bonnie++ 工具学习记录
    Bonnie++工具学习记录文章目录Bonnie++工具学习记录主要特点如何下载安装Bonnie++使用Bonnie++常见使用方式:基本使用:测试并生成报告。测试结果分析:主要使用场景Bonnie++是一款专门用于测试硬盘和文件系统性能的开源工具。它通过模拟各种文件操作来评估存储......
  • 机器学习和深度学习--李宏毅(笔记与个人理解)Day9
    Day9LogisticRegression(内涵,熵和交叉熵的详解)中间打了一天的gta5,图书馆闭馆正好+npy不舒服那天+天气不好,哈哈哈哈哈总之各种理由吧,导致昨天没弄起来,今天补更!这里重点注意一下,这个output值是概率哈,也就是说式子整体表示的含义是x属于c1的概率是多大这个老师......
  • python学习之:数据类型
    大纲:一、列表list的定义语法1、""""演示数据类型:list列表语法:变量=[元素1,元素2,元素3,......]"""#定义一个列表listname_list=['itheima','itcast','python']print(name_list)print(type(name_list))#定义一个嵌套的列表statis......