provide / inject

74 阅读2分钟

概述

Vue 中,当父组件向子组件传递数据时,会使用 Props。但是如果需要向更深层级的组件传递数据的话使用 Props 逐级传递会变得非常繁琐。

provide / inject 是一种高级组件通讯方式, 它可以解决 Props 逐级传递的问题。一个父组件通过 provide 注册依赖,为其所有的后代组件使用,其任何后代组件都通过 inject 注入依赖进行使用。

provide/inject

provide

provide 可以是个 对象 或是 函数

对象类型:

provide: {
  message: "Hello,Vue2!",
}
  • 对象类型的 provide 访问不到 this 实例。
export default {
  provide: {
    message: this.message,
  },
  data() {
    return {
      message: "Hello,Vue2!",
    };
  },

};
  • 上面的例子会报错,如果想要访问组件实例,可以将 provide 定义为函数返回一个对象的方式。

函数类型:

  provide() {
    return {
      message: "Hello,Vue2!"
    };
  },
  • provide 函数可以访问到当前组件实例的 this
export default {
  provide() {
    return {
      message: this.message
    };
  },
  data() {
    return {
      message: "Hello,Vue2!",
    };
  },
};

inject

inject 可以是个 数组对象

Vue2.2.1 或更高版本时,inject 注入的值会在 propsdata 初始化之前。

数组类型:

  • 数组中的每一个元素表示需要注入的属性名。
inject: ["message"]
  • 注入父元素提供的依赖 message,注入后可以直接 this.message 进行访问。

对象类型:

  • 对象类型下有两个选项,分别是:

    • from:注入的属性名。
    • default:默认值。
  • 使用方式:

inject: {
  // 写法1:
  myUser: { // 从祖先组件中注入的 user 名会被重写成 myUser 作用在当前注入属性的组件实例中。
    from: "user", // 注入的属性名
    default: () => ({}), // 默认值
  },
  // 写法2:
  user: { // 注入的属性名
    default: () => ({}), // 默认值
  },
},

使用注意

provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。

父:

<template>
  <div>
    <p>父-user:{{ user.name }}</p>
    <p>父-list:{{ list }}</p>
    <p>父-message:{{ message }}</p>

    <br />

    <Child />
  </div>
</template>

<script>
import Child from "@/components/Child.vue";
export default {
  components: {
    Child,
  },
  provide() {
    return {
      user: this.user, // 会被刷新,传入的是可监听对象
      list: this.list, // 会被刷新,传入的是可监听对象
      message: this.message, // 父元素 message 改变,子元素的 message 并不会被刷新,基本数据类型不具备可响应。
    };
  },
  data() {
    return {
      user: {
        name: "张三",
      },
      message: "",
      list: [1, 2, 3, 4],
    };
  },
  mounted() {
    setTimeout(() => {
      this.user.name = "李四";
      this.list.push(5);
      this.message = "值发生改变";
    }, 2000);
  },
};
</script>

子:

<template>
  <div>
    <p>子-user:{{ user.name }}</p>
    <p>子-list:{{ list }}</p>
    <p>子-message:{{ message }}</p>
  </div>
</template>

<script>
export default {
  inject: {
    user: {
      default: () => ({}),
    },
    list: {
      default: () => [],
    },
    message: {
      default: "",
    },
  },
};
</script>