Vue3通过provide和inject进行通信

82 阅读1分钟

Vue3 通过privide和inject进行组件复杂通信

在项目中,一些简单的父子通信可以通过prop和emit的方式实现,但通信层次较深时或者场景较为复杂时,逐级prop的方式显得非常愚蠢,可以通过provide和inject的方式实现组件通信。

场景:子组件A需要与同级子组件B进行通信

父组件

<template>
  <div class="father_container">
    <Son1 ref="son1" />
    <Son2 ref="son2" />
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, provide } from "vue";
import Son1 from "./Son1.vue";
import Son2 from "./Son2.vue";

// 定义CompRef为一个函数
export type CompRef = () => {
  son1: InstanceType<typeof Son1>;
  son2: InstanceType<typeof Son2>;
};

export default defineComponent({
  name: "Father",
  components: {
    Son1,
    Son2,
  },
  setup() {
    const son1 = ref();

    const son2 = ref();
    
    // provide compRef,为一个函数
    provide("compRef", () => {
     return { son1: son1.value, son2: son2.value }
    });

    return {
      son1,
      son2,
    };
  },
});
</script>

<style lang="scss" scoped></style>

子组件A

<template>
  <div class="son1-container">
    <el-button @click="handleClick">click</el-button>
    <el-button @click="handleChangeOther">改变son2</el-button>
    <el-input v-model="name"></el-input>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, inject, defineExpose } from "vue";
import type { CompRef } from "./Father.vue";

export default defineComponent({
  name: "Son1",

  setup() {
    const compRef = inject("compRef") as CompRef;

    const name = ref("son1");

    const handleClick = () => {
      name.value = name.value + "more_";
    };

    const handleChangeOther = () => {
      console.log('ref',compRef)
      compRef().son2.handleClick();
    };

    defineExpose({
      handleClick
    })

    return {
      name,
      handleClick,
      handleChangeOther
    };
  },
});
</script>

<style lang="scss" scoped></style>

子组件B

<template>
  <div class="son2-container">
    <el-button @click="handleClick">click</el-button>
    <el-button @click="handleChangeOther">改变son1</el-button>
    <el-input v-model="name"></el-input>
  </div>
</template>
<script lang="ts">
import { defineComponent, ref, inject, defineExpose } from "vue";
import type { CompRef } from "./Father.vue";

export default defineComponent({
  name: "Son2",

  setup() {
    const name = ref("son2");

    const compRef = inject('compRef') as CompRef;

    const handleClick = () => {
      name.value = name.value + "more_";
    };

    const handleChangeOther = () => {
      compRef().son1.handleClick();
    };

    defineExpose({
      handleClick
    })

    return {
      name,
      handleClick,
      handleChangeOther
    };
  },
});
</script>

<style lang="scss" scoped></style>