父组件如果需要给子组件传递数据可以使用 props

父组件如果需要给子组件下的子组件传递数据也可以使用 props 把数据传给子组件,然后子组件再把数据通过 props 逐级的传给下面的子组件。

使用 props 逐级传递,如果组件层级不深的话也可以,但如果组件层级较深的话,使用这种层层转发的方式就不太好维护了。

使用 Vuex 和 Pinia 虽然也能解决上面的问题,但如果你只是简单传个数据的话,也没必要引入一个重量级的状态管理库。

Vue3 提供了 provideinject API,使用 provideinject ,祖先组件给后代组件传递数据不再需要层层转发。

provide 分享数据

祖先组件可以使用 provide 把数据分享出去,后代组件可以使用 inject 来接收数据。

provide 分享数据:

<script setup>
import { provide, ref } from 'vue';

provide('message', 'Hello');
provide('count', ref(1));
</script>

provide 的第一个参数是名称ID,后代组件需要通过这个名称ID 来取到数据。第二个参数是数据,数据可以是普通的 String 或 Number 之类的,也可以是 ref 的响应式数据。

如果你不用 script setup 写法的话,provide 需要写在 setup 函数中:

import { provide, ref } from 'vue';

export default {
  setup() {
    provide('message', 'hello');
    provide('count', ref(1));
  }
}

inject 接收数据

后代组件可以使用 inject 来接收 provide 分享的数据。

下面使用 inject 接收上面分享的数据:

<template>
  <div>
    {{ message }}
    {{ count }}
  </div>
</template>

<script setup>
import { inject } from 'vue';

const message = inject('message');
const count = inject('count');
</script>

不使用 script setup

<template>
  <div>
    {{ message }}
    {{ count }}
  </div>
</template>

<script>
import { inject } from 'vue';

export default {
  setup() {
    const message = inject('message');
    const count = inject('count');

    return { message, count };
  }
}
</script>

入口全局 provide

provide 可以在单个组件中使用,也可以在应用入口为所有组件提供数据。

下面再入口 main.js 使用 provide

import { createApp } from 'vue';
import App from './App.vue';

const app = createApp(App);

app.provide('message', 'My blog misterma.com');
app.mount('#app');

所有的组件都可以使用 inject 访问到 main.jsprovide

响应式和数据更改

接收方组件使用 inject 接收数据后是可以对数据进行更改处理的,但是为了便于维护,不建议在接收方更改数据。使用 provide 提供数据的组件在提供数据时可以同时提供一个函数来更改数据。

下面使用 provide 分享数据并提供一个更改数据的函数:

<script setup>
import { provide, ref } from 'vue';

const count = ref(1);  // 要分享的数据
// 用于更改数据的函数
function changeCount() {
  count.value ++;
}

provide('count', { count, changeCount });
</script>

上面使用 provide 分享了一个对象,对象中包含 count 数据和 changeCount 更改数据的函数。

接收方可以使用 changeCount 来更改 count

<script setup>
import { inject } from 'vue';

const count = inject('count');
// 调用 count 的 changeCount 来更改 count
count.changeCount();
// 在控制台输出 count
console.log(count.count.value);
</script>

如果你需要让接收方不能更改数据可以使用 readonly 函数:

<script setup>
import { provide, ref, readonly } from 'vue';

const count = ref(1);
provide('readonly-count', readonly(count));
</script>

接收方还是一样的使用 inject 接收。