关于程序员:Vue3-学习笔记Day5

39次阅读

共计 7126 个字符,预计需要花费 18 分钟才能阅读完成。

写在后面

本文为尚硅谷禹神 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";

// 创立 emitter
const 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); 
*/

// 创立并裸露 mitt
export 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 多平台公布

正文完
 0