Blog
首页
文档
收藏
关于
  • 在线转换时间戳 (opens new window)
  • 在线压缩图片 (opens new window)
  • Float-Double转二进制 (opens new window)
  • 文件转Hex字符串 (opens new window)

HiuZing

🍑
首页
文档
收藏
关于
  • 在线转换时间戳 (opens new window)
  • 在线压缩图片 (opens new window)
  • Float-Double转二进制 (opens new window)
  • 文件转Hex字符串 (opens new window)
  • 前端面试题

  • JavaScript

  • Vue2

  • port

  • CSS

  • Node.js

  • JavaScript优化

  • uniapp

  • Mini Program

  • TypeScript

  • 面向对象编程

  • UI组件

  • Plugin

  • Vue3

    • 教程

      • 创建Vue3工程

      • Composition API

        • setup
        • ref函数
        • reactive函数
        • 响应式原理
        • reactive对比ref
        • setup的两个注意点
        • 计算属性与监视
        • 生命周期
        • 自定义hook函数
        • toRef
        • shallowReactive 与 shallowRef
        • readonly 与 shallowReadonly
        • toRaw 与 markRaw
        • customRef
        • provide 与 inject
        • 响应式数据的判断
        • Vue3通信方式
          • Vue3通信方式
          • props
          • 自定义事件
          • 全局事件总线$bus
          • v-model
          • useAttrs
          • ref与$parent
            • ref
            • $parent
          • provide与inject
          • pinia
            • 选择式API
            • 组合式API
          • slot
            • 默认插槽
            • 具名插槽
            • 作用域插槽
      • Composition API 的优势

      • 新的组件

      • 其他新变化

    • Vue Router

    • API

    • Vuex

    • 实例处理方案

    • 文档

    • 用法

  • 性能优化

  • Axios

  • 状态管理

  • React

  • Mock

  • Icon

  • Template

  • 构建工具

  • 项目规范配置

  • Taro

  • SVG

  • React Native

  • 前端
  • Vue3
  • 教程
  • Composition API
HiuZing
2023-05-30
目录

Vue3通信方式

# Vue3通信方式

  • props
  • 自定义事件
  • 全局事件总线$bus
  • v-model
  • useAttrs
  • ref与$parent
  • provide与inject
  • vuex(pinia)
  • slot
  • pubsub

# props

通过defineProps获取父组件传递的数据

# 自定义事件

一种是原生的DOM事件,另外一种自定义事件

原生DOM事件:click、dbclick、change、mouseenter、mouseleave....

自定义事件:实现子组件给父组件传递数据

在vue3框架click、dbclick、change(这类原生DOM事件),不管是在标签、自定义标签上(组件标签)都是原生DOM事件。

// 父组件
<Event2  @xxx="handler3" @click="handler"></Event2>

// 子组件
let $emit = defineEmits(["xxx",'click']);
1
2
3
4
5

# 全局事件总线$bus

mitt:官网地址:https://www.npmjs.com/package/mitt

  1. 安装

    npm install --save mitt
    
    1
  2. 引入到项目并挂载

    1. 可以在main.js挂载到全局

      // 标准的ES模块化引入方式
      import mitt from 'mitt'
      
      const app = createApp(App)
      
      // vue3.x的全局实例,要挂载在config.globalProperties上
      app.config.globalProperties.$EventBus = new mitt()
      
      1
      2
      3
      4
      5
      6
      7
    2. /common/EventBus.js:也可以封装一个ES模块,对外暴露一个Mitt实例

      import mitt from 'mitt'
      export default new mitt()
      
      1
      2
  3. 使用

    1. 通过on监听/emit触发

      /*
       * App.vue
       */
      // setup中没有this,需要通过getCurrentInstance来获取Vue实例
      import { getCurrentInstance } from 'vue'
      import { Mp3Player } from '/common/Mp3Player.js'
      
      export default {
        setup(){
          // ctx等同于Vue2.x的this
          const { ctx } = getCurrentInstance()
          
          // 监听-如果有新任务则播放音效
          ctx.$EventBus.on('newTask', data => {
            Mp3Player.play()
          })
      
          // 也可以通过*监听所有任务
          ctx.$EventBus.on('*', data => {
            console.log('EventBus come in', data)
          })
        }
      }
      
      /*
       * Control.vue
       */
      // 判断有新任务时,触发
      ctx.$EventBus.emit('newTask', data)
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
    2. off移除事件

# v-model

收集表单数据(数据双向绑定),除此之外它也可以实现父子组件数据同步

利用*props[modelValue]与自定义事件[update:modelValue]*实现的

// 父组件
<Child :modelValue="money" @update:modelValue="handler"></Child>

// 子组件内部
<button @click="handleChild"/>
// 接收props
const props = defineProps(['modelValue'])
// 接收自定义事件
const $emit = defineEmits(['update:modelValue'])
const handleChild = () => {
    // 调用自定义组件给父组件传递参数
    $emit('update:modelValue',props.modelValue + 1000)
}
1
2
3
4
5
6
7
8
9
10
11
12
13

利用v-model

// 相当于传递一个props(modelValue),绑定一个自定义事件update:modelValue
// 实现父子组件数据同步
<Child v-model="msg"></Child>
1
2
3

使用多个v-model,让父子组件多个数据同步

// 传递两个props分别是pageNo与pageSize,绑定两个自定义事件update:pageNo与update:pageSize
// 实现父子组件数据同步
<Child v-model:pageNo="msg" v-model:pageSize="msg1"></Child>
1
2
3

# useAttrs

获取组件的属性与事件(包含:原生DOM事件或者自定义事件)

<my-button type="success" size="small" title='标题' @click="handler"></my-button>
1

在子组件内部

通过useAttrs方法获取组件属性与事件

<template>
	<--可获取全部属性-->
	<my-button :="$attrs"></my-button>
</template>

<script setup lang="ts">
import {useAttrs} from 'vue';
let $attrs = useAttrs();
</script>
1
2
3
4
5
6
7
8
9

警告

如果defineProps接受了某一个属性,useAttrs方法返回的对象身上就没有相应属性与属性值

# ref与$parent

ref:可以获取真实的DOM节点,可以获取到子组件实例VC

$parent:可以在子组件内部获取到父组件的实例

在父组件内部通过ref获取元素的DOM或者获取子组件实例的VC,那么子组件内部的方法与响应式数据父组件可以使用的

# ref

父组件
<div>{{money}}</div>
<button @click="handle">调用子组件内部</button>
<Son ref="son"></Son>

<script>
    let money = ref(10000)
	let son = ref()
	const handle = ()=>{
    	money.value += 100
	    // 调用子组件
    	son.value.moeny -= 100
	}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
子组件内部
<script>
    let money = ref(666)
	// 组件内部数据对外关闭,别人不能访问
    // 如果想让外部访问需要通过defineExpose方法对外暴露
    defineExpose({
        money
    })
</script>
1
2
3
4
5
6
7
8
9

# $parent

父组件
<script>
    let money = ref(666)
	// 组件内部数据对外关闭,别人不能访问
    // 如果想让外部访问需要通过defineExpose方法对外暴露
    defineExpose({
        money
    })
</script>
1
2
3
4
5
6
7
8
9
子组件内部
<template>
	<div>{{money}}</div>
	<button @click="handle($parent)">点击调用父组件方法</button>
</template>
<script>
    let money = ref(666)
    const handle = ($parent)=>{
        money.value += 10
        $parent.money -= 10
    }
</script>
1
2
3
4
5
6
7
8
9
10
11
12

# provide与inject

provide[提供],inject[注入] 实现隔辈组件传递参数

  • provide 提供数据(需要传递两个参数,分别提供数据的key与提供数据value)
  • inject 获取数据(通过key获取存储的数值)
<script setup lang="ts">
import {provide} from 'vue'
provide('token','admin_token');
</script>

// 后代组件
<script setup lang="ts">
import {inject} from 'vue'
let token = inject('token');
</script>
1
2
3
4
5
6
7
8
9
10

# pinia

pinia官网:https://pinia.web3doc.top/

核心概念:state、actions、getters

写法:选择器API、组合式API

# 选择式API

# 创建pinia

  1. 创建大仓库store/index.ts

    import { createPinia } from 'pinia'
    let store = createPinia()
    
    export default store
    
    1
    2
    3
    4
  2. 在入口文件main.ts

    // 引入仓库
    import store from './store'
    
    app.use(store)
    
    1
    2
    3
    4
  3. 创建模块式modules

  4. 创建小仓库modules/info.ts

    import { defineStore } from 'pinia'
    
    // 两个参数:第一个参数 仓库名字,第二个参数 小仓库配置对象
    // defineStore会返回一个函数,函数作用域让组件可以获取到仓库数据
    let useInfoStore = defineStore("info",{
        // 存储数据
        state:() => {
            return {
                count:99,
                arr:[1,2,3]
            }
        },
        actions:{
            // 函数没有context上下文对象
            // 没有commit、没有mutations去修改
            updateNum(a:number){
                this.count+=a
            }
        },
        getters:{
            total(){
                return this.arr.reduce((prev:number,next:number)=>{
                    return prev + next;
                },0)
            }
        }
    })
    export default useInfoStore;
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28

# 使用pinia

<template>
	{{infoState.count}}
	<--直接获取getters-->
	{{infoState.total}}
	<button @click="updateCount">
        点击修改仓库数据
    </button>
</template>

<script setup lang="ts">
import useInfoStore from '../../store/modules/info'
// 获取小仓库对象
let infoState = useInfoStore()

// 修改数据方法
const updateCount = ()=>{
    // 方法一
    infoState.count++
    // 方法二
    infoState.$patch({
        count:111
    })
    // 方法三(调用actions中的方法,类似vuex的dispatch)
    // 仓库调用自身方法去修改仓库数据
    infoState.updateNum(11);
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 组合式API

# 创建pinia

创建小仓库store/modules/todo.ts

import { defineStore } from 'pinia'
import { ref,computed } from 'vue'

let useTodoStore = defineStore('todo',()=>{
    let todos = ref([
        {
            id:1,
            title:'吃饭'
        },
        {
            id:2,
            title:'睡觉'
        },
        {
            id:3,
            title:'打豆豆'
        },
    ])
    let arr = ref([1,2,3])
    
    // 计算属性
    const total = computed(()=>{
        return arr.value.reduce((prev:number,next:number)=>{
            return prev+next
        },0)
    })
    
    // 务必返回一个对象:属性和方法可以提供给组件使用
    return {
        todos,
        arr,
        total,
        updateTodo(){
            todos.value.push({
                id:4,
                title:'组合式API'
            })
        }
    }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

# 使用pinia

<template>
	<p @click="updateTodo">
    	{{todoStore.todos}}
    </p>
	<--计算属性-->
	<div>
        {{todoStore.total}}
    </div>
</template>

<script setup lang="ts">
// 引入组合式API函数仓库
import useTodoStore from '../../store/moudules/todo'
let todoStore = useTodoStore()

// 点击P段落修改仓库
const updateTdo = ()=>{
    todoStore.updateTodo()
}
    
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# slot

插槽:默认插槽、具名插槽、作用域插槽可以实现父子组件通信

# 默认插槽

父组件

<Todo>
  <h1>我是默认插槽填充的结构</h1>
</Todo>
1
2
3

在子组件Todo内部的模板中书写slot全局组件标签

<template>
	<div>
		我是子组件
	    <slot></slot>
        我是子组件
	</div>
</template>
1
2
3
4
5
6
7

# 具名插槽

带有名字在组件内部留多个指定名字的插槽

父组件

<Todo>
	<template v-slot:a>
		<div>
            我是填充具名插槽a的位置结构
        </div>
    </template>
    
	<--简写-->
	<template #b>
		<div>
            我是填充具名插槽b的位置结构
        </div>
    </template>
</Todo>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

子组件Todo

<template>
	<div>
		具名插槽a填充数据
	    <slot name="a"></slot>
        
		具名插槽b填充数据
	    <slot name="b"></slot>
	</div>
</template>
1
2
3
4
5
6
7
8
9

# 作用域插槽

可以理解为子组件数据由父组件提供,但是子组件内部决定不了自身结构与外观(样式)

子组件

<ul>
	<li v-for="(item,index) in todos" :key="item.id">
    	<slot :$row="item" :$index="index"></slot>
    </li>
</ul>
1
2
3
4
5

父组件

<Test :todos="todos">
	<template v-slot="{$row,$index}">
		<span :style="{color:$row.done?'green':'red'}">{{$row.title}}</span>
    </template>
</Test>
1
2
3
4
5
上次更新: 2024/08/14, 04:14:33
响应式数据的判断
Options API 存在的问题

← 响应式数据的判断 Options API 存在的问题→

最近更新
01
React Native 使用SVG
08-13
02
Docker基础命令
08-04
03
算数逻辑单元
07-30
更多文章>
Theme by Vdoing | Copyright © 2021-2024 WeiXiaojing | 友情链接
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式