写在后面
本文为尚硅谷禹神 Vue3 教程的学习笔记。本着本人学习、分享别人的态度,分享学习笔记,心愿能对大家有所帮忙。举荐先按程序浏览往期内容:\
1. Vue3 学习笔记(Day1) \
2. Vue3 学习笔记(Day2) \
3. Vue3 学习笔记(Day3) \
4. Vue3 学习笔记(Day4)
::: block-1
目录
6 组件通信
- 6.1 props
- 6.2 自定义事件
- 6.3 mitt
- 6.4 v-model
- 6.5 $attrs
- 6.6 $refs、$parent
- 6.7 provide、inject
- 6.8 pinia
- 6.9 slot
:::
6 组件通信
P52:https://www.bilibili.com/video/BV1Za4y1r7KE?p=52
Vue3
组件通信和Vue2
的区别:
- 移出事件总线,应用
mitt
代替。 vuex
换成了pinia
。- 把
.sync
优化到了v-model
外面了。 - 把
$listeners
所有的货色,合并到$attrs
中了。 $children
被砍掉了。
常见搭配模式:
6.1 props
概述:props
是应用频率最高的一种通信形式,罕用与 :父 ↔ 子。
- 若 父传子:属性值是非函数。
- 若 子传父:属性值是函数。
父组件:
<template> <div class="father"> <h3>父组件,</h3> <h4>我的车:{{ car }}</h4> <h4>儿子给的玩具:{{ toy }}</h4> <Child :car="car" :getToy="getToy"/> </div></template><script setup lang="ts" name="Father"> import Child from './Child.vue' import { ref } from "vue"; // 数据 const car = ref('飞驰') const toy = ref() // 办法 function getToy(value:string){ toy.value = value }</script>
子组件
<template> <div class="child"> <h3>子组件</h3> <h4>我的玩具:{{ toy }}</h4> <h4>父给我的车:{{ car }}</h4> <button @click="getToy(toy)">玩具给父亲</button> </div></template><script setup lang="ts" name="Child"> import { ref } from "vue"; const toy = ref('奥特曼') defineProps(['car','getToy'])</script>
6.2 自定义事件
P53:https://www.bilibili.com/video/BV1Za4y1r7KE?p=53
- 概述:自定义事件罕用于:子 => 父。
- 留神辨别好:原生事件、自定义事件。
原生事件:
- 事件名是特定的(
click
、mosueenter
等等) - 事件对象
$event
: 是蕴含事件相干信息的对象(pageX
、pageY
、target
、keyCode
)
- 事件名是特定的(
自定义事件:
- 事件名是任意名称
- 事件对象
$event
: 是调用emit
时所提供的数据,能够是任意类型!!!
示例:
<!--在父组件中,给子组件绑定自定义事件:--><Child @send-toy="toy = $event"/><!--留神辨别原生事件与自定义事件中的$event--><button @click="toy = $event">测试</button>
//子组件中,触发事件:this.$emit('send-toy', 具体数据)
6.3 mitt
P54:https://www.bilibili.com/video/BV1Za4y1r7KE?p=54
概述:与音讯订阅与公布(pubsub
)性能相似,能够实现任意组件间通信。
装置mitt
npm i mitt
新建文件:src\utils\emitter.ts
// 引入mitt import mitt from "mitt";// 创立emitterconst emitter = mitt()/* // 绑定事件 emitter.on('abc',(value)=>{ console.log('abc事件被触发',value) }) emitter.on('xyz',(value)=>{ console.log('xyz事件被触发',value) }) setInterval(() => { // 触发事件 emitter.emit('abc',666) emitter.emit('xyz',777) }, 1000); setTimeout(() => { // 清理事件 emitter.all.clear() }, 3000); */// 创立并裸露mittexport default emitter
接收数据的组件中:绑定事件、同时在销毁前解绑事件:
import emitter from "@/utils/emitter";import { onUnmounted } from "vue";// 绑定事件emitter.on('send-toy',(value)=>{ console.log('send-toy事件被触发',value)})onUnmounted(()=>{ // 解绑事件 emitter.off('send-toy')})
【第三步】:提供数据的组件,在适合的时候触发事件
import emitter from "@/utils/emitter";function sendToy(){ // 触发事件 emitter.emit('send-toy',toy.value)}
留神这个重要的内置关系,总线依赖着这个内置关系
6.4 v-model
P55:https://www.bilibili.com/video/BV1Za4y1r7KE?p=55
P56:https://www.bilibili.com/video/BV1Za4y1r7KE?p=56
概述:实现 父↔子 之间互相通信。
前序常识 —— 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
的实质::moldeValue
+ update:modelValue
事件。
<!-- 组件标签上应用v-model指令 --><AtguiguInput v-model="userName"/><!-- 组件标签上v-model的实质 --><AtguiguInput :modelValue="userName" @update:model-value="userName = $event"/>
AtguiguInput
组件中:
<template> <div class="box"> <!--将接管的value值赋给input元素的value属性,目标是:为了出现数据 --> <!--给input元素绑定原生input事件,触发input事件时,进而触发update:model-value事件--> <input type="text" :value="modelValue" @input="emit('update:model-value',$event.target.value)" > </div></template><script setup lang="ts" name="AtguiguInput"> // 接管props defineProps(['modelValue']) // 申明事件 const emit = defineEmits(['update:model-value'])</script>
也能够更换value
,例如改成abc
<!-- 也能够更换value,例如改成abc--><AtguiguInput v-model:abc="userName"/><!-- 下面代码的实质如下 --><AtguiguInput :abc="userName" @update:abc="userName = $event"/>
AtguiguInput
组件中:
<template> <div class="box"> <input type="text" :value="abc" @input="emit('update:abc',$event.target.value)" > </div></template><script setup lang="ts" name="AtguiguInput"> // 接管props defineProps(['abc']) // 申明事件 const emit = defineEmits(['update:abc'])</script>
如果value
能够更换,那么就能够在组件标签上屡次应用v-model
<AtguiguInput v-model:abc="userName" v-model:xyz="password"/>
6.5 $attrs
P57:https://www.bilibili.com/video/BV1Za4y1r7KE?p=57
概述:$attrs
用于实现以后组件的父组件,向以后组件的子组件通信(祖→孙)。
具体阐明:$attrs
是一个对象,蕴含所有父组件传入的标签属性。
留神:$attrs
会主动排除props
中申明的属性(能够认为申明过的 props
被子组件本人“生产”了)
父组件:
<template> <div class="father"> <h3>父组件</h3> <Child :a="a" :b="b" :c="c" :d="d" v-bind="{x:100,y:200}" :updateA="updateA"/> </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) let d = ref(4) function updateA(value){ a.value = value }</script>
子组件:
<template> <div class="child"> <h3>子组件</h3> <GrandChild v-bind="$attrs"/> </div></template><script setup lang="ts" name="Child"> import GrandChild from './GrandChild.vue'</script>
孙组件:
<template> <div class="grand-child"> <h3>孙组件</h3> <h4>a:{{ a }}</h4> <h4>b:{{ b }}</h4> <h4>c:{{ c }}</h4> <h4>d:{{ d }}</h4> <h4>x:{{ x }}</h4> <h4>y:{{ y }}</h4> <button @click="updateA(666)">点我更新A</button> </div></template><script setup lang="ts" name="GrandChild"> defineProps(['a','b','c','d','x','y','updateA'])</script>
6.6 $refs
、$parent
P58:https://www.bilibili.com/video/BV1Za4y1r7KE?p=58
P59:https://www.bilibili.com/video/BV1Za4y1r7KE?p=59
概述:
$refs
用于 :父→子。$parent
用于:子→父。
原理如下:
属性 | 阐明 |
---|---|
$refs | 值为对象,蕴含所有被ref 属性标识的DOM 元素或组件实例。 |
$parent | 值为对象,以后组件的父组件实例对象。 |
6.7 provide、inject
P60:https://www.bilibili.com/video/BV1Za4y1r7KE?p=60
概述:实现祖孙组件间接通信
具体应用:
- 在先人组件中通过
provide
配置向后辈组件提供数据 - 在后辈组件中通过
inject
配置来申明接收数据
具体编码:
【第一步】父组件中,应用provide
提供数据
<template> <div class="father"> <h3>父组件</h3> <h4>资产:{{ money }}</h4> <h4>汽车:{{ car }}</h4> <button @click="money += 1">资产+1</button> <button @click="car.price += 1">汽车价格+1</button> <Child/> </div></template><script setup lang="ts" name="Father"> import Child from './Child.vue' import { ref,reactive,provide } from "vue"; // 数据 let money = ref(100) let car = reactive({ brand:'飞驰', price:100 }) // 用于更新money的办法 function updateMoney(value:number){ money.value += value } // 提供数据 provide('moneyContext',{money,updateMoney}) provide('car',car)</script>
【第二步】孙组件中应用inject
配置项承受数据
<template> <div class="grand-child"> <h3>我是孙组件</h3> <h4>资产:{{ money }}</h4> <h4>汽车:{{ car }}</h4> <button @click="updateMoney(6)">点我</button> </div></template><script setup lang="ts" name="GrandChild"> import { inject } from 'vue'; // 注入数据 let {money,updateMoney} = inject('moneyContext',{money:0,updateMoney:(x:number)=>{}}) let car = inject('car')</script>
6.8 pinia
参考之前pinia
局部的解说
6.9 slot
1. 默认插槽
P61:https://www.bilibili.com/video/BV1Za4y1r7KE?p=61
父组件中:
<Category title="今日热门游戏"> <ul> <li v-for="g in games" :key="g.id">{{ g.name }}</li> </ul></Category>
子组件中:
<template> <div class="item"> <h3>{{ title }}</h3> <!-- 默认插槽 --> <slot></slot> </div></template>
2. 具名插槽
P62:https://www.bilibili.com/video/BV1Za4y1r7KE?p=62
父组件中:
<Category title="今日热门游戏"> <template v-slot:s1> <ul> <li v-for="g in games" :key="g.id">{{ g.name }}</li> </ul> </template> <template #s2> <a href="">更多</a> </template></Category>
子组件中:
<template> <div class="item"> <h3>{{ title }}</h3> <slot name="s1"></slot> <slot name="s2"></slot> </div></template>
3. 作用域插槽
P63:https://www.bilibili.com/video/BV1Za4y1r7KE?p=63
了解:数据在组件的本身,但依据数据生成的构造须要组件的使用者来决定。(新闻数据在News
组件中,但应用数据所遍历进去的构造由App
组件决定)
父组件中:
<Game v-slot="params"><!-- <Game v-slot:default="params"> --><!-- <Game #default="params"> --> <ul> <li v-for="g in params.games" :key="g.id">{{ g.name }}</li> </ul></Game>
子组件中:
<template> <div class="category"> <h2>今日游戏榜单</h2> <slot :games="games" a="哈哈"></slot> </div></template><script setup lang="ts" name="Category"> import {reactive} from 'vue' let games = reactive([ {id:'asgdytsa01',name:'英雄联盟'}, {id:'asgdytsa02',name:'王者光荣'}, {id:'asgdytsa03',name:'红色警戒'}, {id:'asgdytsa04',name:'斗罗大陆'} ])</script>
<center>完结</center>
本文由mdnice多平台公布