Vue3.2+Ts组件之间通信的实现

目录
  • 父子组件通信
    • 1、defineProps
    • 2、defineEmits
    • 3、defineExpose
    • 4、v-model
  • 兄弟组件通信
    • 跨组件通信
      • Provide/Inject

    受疫情影响,居家办公有一阵了,最近闲下来开始谈谈自己对于Vue3.2 + TS 知识的理解和使用。今天就总结下项目中常用到的一些组件之间的通信。

    vue框架提供了前端开发组件的思想,页面由一个个组件组合而成,在一些大型项目中,组件的数量越来越多,之间也需要通信,接下来我们进入主题,谈谈vue3.x + ts中如何使用组件通信。
    (vue3.x中组件之间通信和2基本上差别不大,就是基于ts写法可能有点差别。)

    父子组件通信

    1、defineProps

    Parent

    <template>
      <child :count= "countNum" :labels="labels" />
    </template>
    <script setup lang="ts">
    import child from "@/componets/child.vue"
    import { ref } from "vue"
    const countNum = ref(100);
    const labels = ref([])
    </script>

    Child

    <template>
      <div>{{count}}</div>
    </template>
    <script setup lang="ts">
    //这里我们使用typescript的写法
    type TData = { count:number,labels:string[] } //声明父组件传过来的数据以及类型
    //这种写法无法设定默认值
    const props = defineProps<TData>()
    //声明默认值的写法
    const props = withDefaults( defineProps<TData>(), {
      count:1,
      labels:() => ["默认值1","默认值2"]  //对于复杂数据类型以函数式声明
    })
    console.log(props.count) // 模版中直接可以获取值
    </script>

    2、defineEmits

    Parent

    <template>
      <child @changeHandle="changeHandle" />
    </template>
    <script setup lang="ts">
    import child from "@/componets/child.vue"
    const changeHandle = ((e) =>{
      console.log(e)
    })
    </script>

    Child

    <template>
      <div @click="btnHandle">按钮点击</div>
    </template>
    <script setup lang="ts">
    import { ref } from "vue"
    const count = ref(100);
    //typescript的写法
    type TFn = { 
      (e:'changeHandle',value:number) : void
    }
    const emit = defineEmits<TFn>()
    const btnHandle = (() => {
      emit('changeHandle',count)
    })
    //非typescript的写法
    const emit = defineEmits(["changeHandle"])
    const btnHandle = (() => {
      emit('changeHandle',count)
    })
    </script>

    3、defineExpose

    文档是这么介绍的:

    使用 <script setup> 的组件是默认关闭的,也即通过模板 ref 或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。为了在 <script setup> 组件中明确要暴露出去的属性,使用 defineExpose 编译器宏,(其实可以理解为父组件想获取子组件的内容,子组件通过defineExpose把内容暴露出去)

    Parent

    <template>
      <child ref="getChild" />
      <div @click="btnHandle">按钮点击</div>
    </template>
    <script setup lang="ts">
    import child from "@/componets/child.vue"
    const getChild = ref(null)
    const btnHandle = () => {
      //通过ref获取子组件暴露出来的内容
      console.log(getChild.value.count)
      console.log(getChild.value.btnHandle())
    }
    </script>

    Child

    <template>
      <div @click="btnHandle">按钮点击</div>
    </template>
    <script setup lang="ts">
    import { ref } from "vue"
    const count = ref(100);
    const btnHandle = () => {
      count++
    }
    defineExpose({count,btnHandle})
    </script>

    4、v-model

    父子之间通信,有时需要子组件修改父组件传递过来的内容,使用defineProps穿过来的值,进行修改会报错,我在vue2.x中通过watch监听,然后把新值赋值data内自定义属性。
    在vue3.x中我们可以通过v-model的传递并可以进行修改值,我们直接操作吧!

    <template>
      <A v-model:count="count"></A>
    </template>
    <script setup lang="ts">
    import A from "@/components/A.vue"
    import { ref } from "vue"
    const count = ref(100);
    </script>
    
    <template>
      <div>{{count}}</div>
      <div @click="updateHandle">修改内容</div>
    </template>
    <script setup lang="ts">
    import { ref } from "vue"
    const props = defineProps<{count:number}>()
    //修改
    const emit = defineEmits(["update:count"])
    const updateHandle = () => {
      emit("update:count",10)
    }
    </script>

    兄弟组件通信

    在vue2.x中我们一般用中央事件总线(eventBus)来处理兄弟组件,在vue3中用mitt()来处理兄弟组件之间的通信,实际用法和eventBus是一样的,我们来看看如何实现吧

    mitt

    第一步安装:

    yarn add mitt -S

    第二步创建

    //在src/utils创建eventBus.ts
    import mitt from "mitt"
    const mitter = mitt()
    default export mitter

    第三步使用

    //兄弟A组件
    <template>
      <div @click="btnHandle">按钮点击</div>
    </template>
    <script setup lang="ts">
    import mitter from "@/utils/eventBus.ts"
    import { ref } from "vue"
    const count = ref(100)
    mitter.emit("count",count.value)
    </script>
    
    //兄弟B组件
    <template>
      <div @click="btnHandle">按钮点击</div>
    </template>
    <script setup lang="ts">
    import mitter from "@/utils/eventBus.ts"
    import { ref } from "vue"
    const getCount = ref()
    mitter.on("count",(e) => {
      getCount.value = e
    })
    </script>

    跨组件通信

    Provide/Inject

    往往在业务中会存在跨组件之间的通信,有的同学可能会想到一层层通过defineProps传递,这样是可以实现,但是随着项目的代码量庞大很难做到维护。

    //provide 接收两个参数 1、name<String类型> 2、value
    <template>
      <A></A> 
    </template>
    <script setup lang="ts">
    import mitter from "@/utils/eventBus.ts"
    import A from "@/components/A.vue"
    import { provide } from "vue"
    const count = ref(190)
    provide('count',count.value)
    </script>
    
    <!--A组件内的B组件-->
    //inject 接收两个参数 1、provide传如果来的name 2、可选参数,提供默认值
    <template>
      <div>我是B组件</div>
    </template>
    <script setup lang="ts">
    import mitter from "@/utils/eventBus.ts"
    import { inject } from "vue"
    const getCount = inject('count',11)
    </script>

    本文转自网络,如有侵权请联系客服删除。