写在后面

本文为尚硅谷禹神 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
  1. 概述:自定义事件罕用于:子 => 父。
  2. 留神辨别好:原生事件、自定义事件。
  3. 原生事件:

    • 事件名是特定的(clickmosueenter等等)
    • 事件对象$event: 是蕴含事件相干信息的对象(pageXpageYtargetkeyCode
  4. 自定义事件:

    • 事件名是任意名称
    • 事件对象$event: 是调用emit时所提供的数据,能够是任意类型!!!
  5. 示例:

    <!--在父组件中,给子组件绑定自定义事件:--><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的实质::moldeValueupdate: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多平台公布