vue3-02-vue3中的组件通信

目录

该篇内容是我看b站尚硅谷vue3视频总结的,内容仅是我自己总结使用,所以可能有错误和不完善的地方

组件通信

一、vue3组件通信和vue2的区别

常见搭配形式:

二、父子通信

父子通信的方法有3种:

  • props
  • v-model
  • refs、parent

2.1 props通信

1)父→子传递数据(父组件向子组件传递数据)
2)子→父传递数据
  1. 利用参数传值
    注意:下图中传参的方式,父组件把sendToy参数传给子组件,当一点击子组件的button,toy就会传给sendToy,父组件的sendToy触发getToy函数,getToy函数里的value就是我们传递的toy

自定义事件

上述中儿子给父亲传值,利用参数传值太麻烦,可以借助自定义事件来实现

注意,参数传值用的是冒号:,事件用的是@

利用自定义事件

上诉例子利用自定义事件来写:

2.2 v-model

概述: 实现父 ↔ 子之间相互通信
v-model和props的区别:

  • v-model是父子之间控制同一个数据,且这个数据是双向绑定的,其中一方修改另一方会自动修改
  • props是向对方传递自己的数据,例如父组件把自己的car传递给子组件
1)v-model的本质

Father.vue

v-model用在组件标签上,子组件接收并向父组件发送数据,完成双向绑定:

Child.vue

2)给modelValue起别名
  • 父组件引入子组件标签,在子组件标签上通过modelValue进行传值,子组件接收也是通过modelValue接收
  • 但是有时候我们传值的时候,参数名不想用modelValue,可以通过下列方式,给modelValue起别名
  • 起别名还有另外一个重要作用:可以v-model绑定多个数据

Father.vue

Child.vue

3)$event



2.3 父子修改对方的数据

1)父修改子的数据
  1. 父单独修改某个子组件的数据

注意:

  • ref 用在普通DOM标签上,获取的是DOM节点
  • ref 用在组件标签上(如下例),获取的是组件实例对象
  1. 父一下子修改所有子组件的数据
    注意:$refs 可以用于获取父组件的所有子组件的实例对象
2)子修改父的数据

注意:$parent 可以获取子组件的父组件

三、 祖孙通信

有两种方法:

1.$attrs

2.provide、inject

3.1 $attrs

说明:

  • 组件关系说明:祖、父、孙(爷爷、爸爸、孙子)
  • 想要通过$attrs实现祖→孙通信,必须借助父组件
  • 祖把数据传给父,被父组件接收的值在props中,未被接收的值在 a t t r s 中,父组件把 attrs中,父组件把 attrs中,父组件把attrs中的值传给孙,孙接收数据

举例:

3.2 provide、inject

概述: 实现祖孙组件之间直接通信

和$attrs的区别:

  • $attrs需要借助父组件,而且父如果接收祖传的数据,那么这个数据孙就接收不到了
  • provide、inject可以实现祖孙之间直接通信,不需要借助父组件
  • 祖(爷爷)组件中provide提供的数据,所有后代(包括父、孙、重孙...)都可以接收
    使用步骤:
  • 在祖(爷爷)组件中通过provide配置向后代组件提供数据
  • 在后代组件中通过inject配置来声明接收数据
    举例:

四、 任意组件之间通信

任意组件之间的通信有两种方法:

  • mitt
  • pinia

4.1 mitt

概述: 与消息订阅与发布(pubsub)功能类似,可以实现任意组件间通信
说明: 相当于有了一个第三方,双方借助这个第三方进行通信
使用步骤:

1.安装mitt:npm install mitt

2.配置src/utils/emitter.ts

3.提供数据的组件:在合适的时候触发事件,然后提供数据

4.接受数据的组件:绑定事件,同时在销毁前解绑事件

举例:(注意每个组件中都要引入第三方,也就是emitter)

4.2 pinia

1. 搭建pinia环境

注意:pinia相当于vue2中的vuex,是状态管理工具

2. 存储数据

用法:(两种写法)

写法一:选项式

count.ts

javascript 复制代码
// 引入defineStore用于创建store
import {defineStore} from 'pinia'

// 定义并暴露一个store
export const useCountStore = defineStore('count',{

  // 状态---相当于data
  state(){
    return {
      sum:6
    }
  },
  // 动作---相当于methods
  actions: {
    increament(value:number) {
      if(value < 10) {
        this.sum += value
      }
    }
  },
  // 计算---相当于computed
  getters: {
    sumAll(state) {
      return this.sum + this.tall + this.age
    }
  }
})
写法二:组合式
javascript 复制代码
import { defineStore } from "pinia"
import axios from 'axios'
import {nanoid} from 'nanoid'

// 选项式
// export const useTalkStore = defineStore('loveTalk', {
//   state() {
//     return {
//       talkList: JSON.parse(localStorage.getItem('talkList') as string) || []
//     }
//   },
//   actions: {
//     async getTalk() {
//     // 发请求,下面这行的写法是:连续解构赋值+重命名
//     let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
//     // 把请求回来的字符串,包装成一个对象
//     let obj = {id:nanoid(),title}
//     // 放到数组中
//     this.talkList.unshift(obj)
//     }
//   }
// })

// 组合式
import {reactive} from 'vue'
export const useTalkStore = defineStore('loveTalk', () => {
  const talkList = reactive(JSON.parse(localStorage.getItem('talkList') as string) || [])

    async function getTalk() {
    // 发请求,下面这行的写法是:连续解构赋值+重命名
    let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
    // 把请求回来的字符串,包装成一个对象
    let obj = {id:nanoid(),title}
    // 放到数组中
    this.talkList.unshift(obj)
    }

    return { talkList, getTalk}
})
3. 读取 / 使用数据

count.vue读取count.ts中的数据 --- 使用state、actions、getters里的数据,使用$subscirbe()监视state里的数据变化

count.ts

javascript 复制代码
import { defineStore } from "pinia"
export const useCountStore = defineStore('count', {
  state() {
    return {
      sum: 0,
      tall: 100,
      age: 18
    }
  },
  actions: {
    increament(value:number) {
      if(value < 10) {
        this.sum += value
      }
    }
  },
  // getters:相当于计算属性
  getters: {
    sumAll(state) {
      return this.sum + this.tall + this.age
    }
  }
})

count.vue

javascript 复制代码
<h2>当前求和为:{{ sum }},tall:{{ tall }},Age:{{ age }},所有总和为:{{ sumAll }}</h2>
<button @click="add">加</button>
<button @click="minus">减</button>
...
  import { ref } from "vue"
  import {useCountStore} from '@/store/count'
  import { storeToRefs } from 'pinia'
  
  
  // *********使用state里的数据   --  在html标签里通过{{ XXX }}使用即可*************
  const countStore = useCountStore()
  // 这里不用toRefs的原因是:如果使用toRefs,则countStore里的所有数据,包括state、actions、getters全部变为响应式数据了,storeToRefs只会将数据做转换
  const { sum, tall, age, sumAll } = storeToRefs(countStore) // 把countStore里的sum, tall, age, sumAll转为响应式数据
  
  
  // **********使用actions里定义的函数*********************
  function add(){
    countStore.increament(n.value)
  }
  
  
    // **************使用getters里面的数据*******************
    // 我们在上面已经通过const { sum, tall, age, sumAll } = storeToRefs(countStore)引入了sumAll,在html标签里可以像state里的数据一样使用   
    
    // 通过store的$subscribe()方法监听state及其变化
    countStore.$subscribe(() => {
    console.log('state里的数据发生变化了')
  })
4. 修改数据

三种方法:

javascript 复制代码
  function add(){
    // 第一种方法 -- 单个数据,直接修改
    countStore.sum += n.value
    // 第二种方法 -- 多个数据,批量修改
    countStore.$patch({
       sum: 200,
       tall: 180,
       age: 80
     })

    // 第三种方法  --  使用actions里定义的函数(actions中可以编写一些业务逻辑)
    countStore.increament(n.value)
  }
5. 补充

nanoid安装命令:npm install nanoid

作用:生成唯一值

引入:import {nanoid} from nanoid

使用:let obj = { id:nanoid(),name:'张三',age:18 }

相关推荐
Leyla10 分钟前
【代码重构】好的重构与坏的重构
前端
影子落人间13 分钟前
已解决npm ERR! request to https://registry.npm.taobao.org/@vant%2farea-data failed
前端·npm·node.js
世俗ˊ38 分钟前
CSS入门笔记
前端·css·笔记
子非鱼92138 分钟前
【前端】ES6:Set与Map
前端·javascript·es6
6230_42 分钟前
git使用“保姆级”教程1——简介及配置项设置
前端·git·学习·html·web3·学习方法·改行学it
想退休的搬砖人1 小时前
vue选项式写法项目案例(购物车)
前端·javascript·vue.js
加勒比海涛1 小时前
HTML 揭秘:HTML 编码快速入门
前端·html
啥子花道1 小时前
Vue3.4 中 v-model 双向数据绑定新玩法详解
前端·javascript·vue.js
麒麟而非淇淋1 小时前
AJAX 入门 day3
前端·javascript·ajax
茶茶只知道学习1 小时前
通过鼠标移动来调整两个盒子的宽度(响应式)
前端·javascript·css