Vue3-跨层组件通信Provide/Inject机制详解

Vue 3 中的 ProvideInject 机制是专为跨层级传递数据而设计的,适用于祖先组件和后代组件之间的通信。与propsemits 不同,Provide/Inject 可以跨越多个层级进行数据传递,而不需要逐层传递。

1. Provide

provide 是一个在祖先组件中提供数据的方法,它将数据传递给该组件的所有后代组件(不需要直接的父子关系)。provide 通常在组件的 setup 函数中使用。

2. Inject

inject 是在后代组件中获取祖先组件提供的数据的方法。inject 也是在 setup 函数中使用,后代组件通过 inject 来访问祖先组件的 provide 数据。

基本使用

步骤 1:在祖先组件中使用 provide 提供数据

祖先组件通过 provide 将数据提供给后代组件。

javascript 复制代码
// Parent.vue
<template>
  <Child />
</template>

<script>
import { provide } from 'vue';
import Child from './Child.vue';

export default {
  components: { Child },
  setup() {
    // 提供数据
    const message = "Hello from Parent!";
    provide('message', message);  // 'message' 是标识符,message 是提供的值
  }
};
</script>

在上面的例子中,Parent 组件通过 provide 提供了一个名为 message 的数据,值是字符串 "Hello from Parent!"。任何后代组件都可以通过 inject 来访问这个数据。

步骤 2:在后代组件中使用 inject 获取数据

后代组件通过 inject 来访问祖先组件提供的数据。

javascript 复制代码
// Child.vue
<template>
  <div>{{ message }}</div>
</template>

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

export default {
  setup() {
    const message = inject('message');  // 使用 inject 获取数据
    return { message };
  }
};
</script>

在上面的代码中,Child 组件通过 inject 获取祖先组件 Parent 提供的 message 数据,并将其渲染在模板中。

如何通过后代组件修改上级组件的值

在 Vue 中,provide 传递的数据是响应式的,但它只提供了只读数据。若要让后代组件修改上级组件的数据,可以通过 provide 传递一个可变的对象或函数来实现。这也可以用来在后代组件中修改祖先组件的状态。

1. 传递响应式数据

你可以通过 reactiveref 将响应式数据传递给后代组件,这样后代组件就可以通过修改响应式数据来更改祖先组件的状态。

javascript 复制代码
// Parent.vue
<template>
  <Child />
  <div>{{ message.text }}</div> <!-- 显示修改后的数据 -->
</template>

<script>
import { reactive, provide } from 'vue';
import Child from './Child.vue';

export default {
  components: { Child },
  setup() {
    // 提供响应式对象
    const message = reactive({ text: "Hello from Parent!" });
    provide('message', message);  // 提供响应式对象

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

Parent 组件中,使用 reactive 创建了一个响应式对象 message,并通过 provide 提供给后代组件。接下来,后代组件就可以修改这个对象的内容。

2. 在后代组件中修改响应式数据

后代组件可以直接修改由 provide 提供的响应式对象的数据, 因为这违背了组件通信中单向数据流的规范,所以不推荐直接在后代组件中直接修改来自上级数据的值。

javascript 复制代码
// Child.vue
<template>
  <button @click="changeMessage">Change Message</button>
</template>

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

export default {
  setup() {
    const message = inject('message');  // 获取祖先组件提供的响应式对象

    // 修改 message 对象中的值
    const changeMessage = () => {
      message.text = "Updated message from Child!";
    };

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

Child 组件中,通过 inject 获取祖先组件提供的响应式对象 message,并提供一个方法 changeMessage 来修改 message.text。由于 message 是响应式的,修改后会自动更新祖先组件中的视图。

通过函数传递数据

除了传递响应式对象外,另一个常见的方法是传递修改数据的函数。这样可以控制后代组件如何修改上级组件的值。

1. 祖先组件传递函数
javascript 复制代码
// Parent.vue
<template>
  <Child />
  <div>{{ message }}</div>  <!-- 显示修改后的数据 -->
</template>

<script>
import { ref, provide } from 'vue';
import Child from './Child.vue';

export default {
  components: { Child },
  setup() {
    const message = ref("Hello from Parent!");

    // 提供修改数据的函数
    const changeMessage = (newMessage) => {
      message.value = newMessage;
    };

    provide('changeMessage', changeMessage);  // 提供修改函数

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

Parent 组件中,我们通过 provide 提供了一个函数 changeMessage,它接收一个新的消息并修改 message 的值。

2. 后代组件调用函数修改数据
javascript 复制代码
// Child.vue
<template>
  <button @click="changeParentMessage">Change Parent Message</button>
</template>

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

export default {
  setup() {
    const changeMessage = inject('changeMessage');  // 获取修改数据的函数

    // 调用函数修改父组件的值
    const changeParentMessage = () => {
      changeMessage("Message updated from Child!");
    };

    return { changeParentMessage };
  }
};
</script>

Child 组件中,通过 inject 获取 changeMessage 函数,并在按钮点击时调用它来修改父组件的 message

总结

  • provide:在祖先组件中提供数据,供后代组件使用。
  • inject:在后代组件中接收祖先组件提供的数据。
  • 响应式数据传递 :你可以传递响应式数据对象(如 reactiveref),使得后代组件修改这些数据会反映到祖先组件。
  • 函数传递:通过提供修改函数,后代组件可以控制数据的修改,从而影响祖先组件的状态。

Provide/Inject 机制非常适合跨越多个层级的组件通信,并且能够避免通过多层级的 props 传递,减少了组件间的耦合度。

相关推荐
月小满2 分钟前
DataV轮播时其他组件的内容也一起滚动 修复bug的方法
前端·vue.js·bug·大屏端
小莫分享23 分钟前
Github Action 一键部署HTML 静态服务
前端·html·github
p***434836 分钟前
JavaScript数据分析实战
开发语言·javascript·ecmascript
星释36 分钟前
Rust 练习册 66:密码方块与文本加密
java·前端·rust
IT_陈寒1 小时前
React性能翻倍!90%开发者忽略的5个Hooks最佳实践
前端·人工智能·后端
亿元程序员1 小时前
光图片就300多M,微信小游戏给再大的分包也难啊!
前端
中工钱袋1 小时前
前端请求到底是从哪里发出去的?
前端
じòぴé南冸じょうげん4 小时前
若依框架favicon.ico缓存更新问题解决方案:本地生效但线上未更新
前端·javascript·前端框架·html
狮子座的男孩4 小时前
js基础高级:01、数据类型(typeof、instanceof、===的使用)、数据与变量与内存(定义、赋值与内存关系、引用变量赋值、js调函数传参)
前端·javascript·经验分享·数据类型·数据与变量与内存·赋值与内存关系·引用变量赋值
Cyclo-7 小时前
PDFJS 在React中的引入 使用组件打开文件流PDF
前端·react.js·pdf