Vue 3 中如何使用 provide 和 inject 实现依赖注入?

在 Vue 3 中,provideinject 是一对用于实现依赖注入的 API。它们提供了一种方式,让祖先组件能够向其所有子孙后代组件注入依赖,而无需通过 props 逐层传递。这在开发大型复杂应用时,尤其是当组件层级较深时,可以极大地简化代码和提高可维护性。

1. 基本用法

1.1 provide

provide 选项应该是一个对象或返回一个对象的函数。该对象包含可注入其子级的属性。你可以将这些属性视为从祖先组件"提供"给后代组件的值或函数。

setup 函数内部使用 provide 时,需要从 vue 包中导入它。

复制代码

javascript复制代码

|---|----------------------------------------|
| | import { provide, ref } from 'vue'; |
| | |
| | export default { |
| | setup() { |
| | const theme = ref('dark'); |
| | |
| | provide('theme', theme); |
| | |
| | // 其他逻辑... |
| | }, |
| | }; |

setup 之外,你可以直接在组件选项中定义 provide

复制代码

javascript复制代码

|---|-----------------------|
| | export default { |
| | data() { |
| | return { |
| | theme: 'dark', |
| | }; |
| | }, |
| | provide() { |
| | return { |
| | theme: this.theme, |
| | }; |
| | }, |
| | }; |

1.2 inject

inject 函数用来在子组件中接收由祖先组件通过 provide 提供的值。第一个参数是提供的 key(字符串),第二个参数是可选的默认值。

setup 函数中使用 inject

复制代码

javascript复制代码

|---|-----------------------------------------------------------------------------|
| | import { inject } from 'vue'; |
| | |
| | export default { |
| | setup() { |
| | const theme = inject('theme', 'light'); // 如果没有注入 'theme',则使用默认值 'light' |
| | |
| | // 使用 theme... |
| | }, |
| | }; |

2. 高级用法

2.1 响应性

在 Vue 3 中,通过 refreactivecomputed 提供的值是响应性的,意味着当提供的值改变时,任何使用 inject 接收该值的组件都将更新。

2.2 符号作为 key

为了避免 key 冲突,你可以使用 Symbol 作为 provide 和 inject 的 key。这确保了你的 provide 是唯一的,不会被其他组件意外覆盖。

复制代码

javascript复制代码

|---|--------------------------------------------------------|
| | import { inject, provide, ref, Symbol } from 'vue'; |
| | |
| | const ThemeSymbol = Symbol('theme'); |
| | |
| | export default { |
| | setup() { |
| | const theme = ref('dark'); |
| | provide(ThemeSymbol, theme); |
| | // ... |
| | }, |
| | }; |
| | |
| | // 在子组件中 |
| | export default { |
| | setup() { |
| | const theme = inject(ThemeSymbol, 'light'); |
| | // 使用 theme... |
| | }, |
| | }; |

2.3 provide 的函数形式

provide 也可以是一个返回对象的函数,这在结合 setup 函数中的响应性状态时非常有用。函数将接收组件的 propscontext 参数。

然而,通常直接在 setup 函数内部使用 provide 函数形式是不必要的,因为你可以直接访问响应性状态和函数。但如果你需要在 setup 之外定义 provide,并且需要访问组件实例(如 this),则函数形式是有用的。

不过,在 Vue 3 的组合式 API 中,你通常会直接在 setup 函数内部工作,因此不太可能需要这种用法。

3. 注意事项

  • 不是响应式的值(如基本类型的字面量、普通的对象等)在传递给 provide 后将不会更新子组件中的相应值,除非它们被封装成响应式对象(如使用 refreactive)。
  • 尽量避免在应用中过度使用依赖注入,因为它可以使组件间的关系变得难以追踪和理解。通常,在开发大型库或框架时,依赖注入才显得尤为有用。
  • provideinject 主要用于开发高阶组件、库或高级用途。在日常开发中,应优先考虑使用 propsemit 来传递数据和事件。
  • 当使用 provideinject 时,确保提供清晰的文档和类型定义(如果使用 TypeScript),以帮助其他开发者理解这些依赖是如何工作的。

4. 示例:主题切换器

下面是一个简单的例子,演示了如何使用 provideinject 在 Vue 3 应用中实现主题切换功能。

祖先组件(App.vue):

复制代码

vue复制代码

|---|----------------------------------------------------------------|
| | <template> |
| | <div :class="theme"> |
| | <ThemeSwitcher /> |
| | <MainContent /> |
| | </div> |
| | </template> |
| | |
| | <script> |
| | import { ref, provide } from 'vue'; |
| | import ThemeSwitcher from './components/ThemeSwitcher.vue'; |
| | import MainContent from './components/MainContent.vue'; |
| | |
| | export default { |
| | components: { |
| | ThemeSwitcher, |
| | MainContent, |
| | }, |
| | setup() { |
| | const theme = ref('light'); |
| | |
| | const toggleTheme = () => { |
| | theme.value = theme.value === 'light' ? 'dark' : 'light'; |
| | }; |
| | |
| | provide('theme', theme); |
| | provide('toggleTheme', toggleTheme); |
| | |
| | return { theme }; |
| | }, |
| | }; |
| | </script> |
| | |
| | <style> |
| | .light { |
| | background-color: white; |
| | color: black; |
| | } |
| | |
| | .dark { |
| | background-color: black; |
| | color: white; |
| | } |
| | </style> |

子组件(ThemeSwitcher.vue):

复制代码

vue复制代码

|---|-------------------------------------------------------|
| | <template> |
| | <button @click="toggleTheme">Switch Theme</button> |
| | </template> |
| | |
| | <script> |
| | import { inject } from 'vue'; |
| | |
| | export default { |
| | setup() { |
| | const toggleTheme = inject('toggleTheme'); |
| | |
| | return { toggleTheme }; |
| | }, |
| | }; |
| | </script> |

另一个子组件(MainContent.vue):

复制代码

vue复制代码

|---|----------------------------------------|
| | <template> |
| | <div> |
| | <p>This is the main content.</p> |
| | <p>Current theme: {``{ theme }}</p> |
| | </div> |
| | </template> |
| | |
| | <script> |
| | import { inject } from 'vue'; |
| | |
| | export default { |
| | setup() { |
| | const theme = inject('theme'); |
| | |
| | return { theme }; |
| | }, |
| | }; |
| | </script> |

在这个例子中,App.vue 组件提供了 theme 响应式引用和 toggleTheme 函数。然后,任何子组件都可以通过 inject 来接收并使用这些值或函数。ThemeSwitcher.vue 组件注入并使用 toggleTheme 函数来切换主题,而 MainContent.vue 组件则注入并显示当前的主题。

相关推荐
耶啵奶膘13 分钟前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^2 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie2 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic3 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿3 小时前
webWorker基本用法
前端·javascript·vue.js
cy玩具3 小时前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
customer084 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
清灵xmf4 小时前
TypeScript 类型进阶指南
javascript·typescript·泛型·t·infer
小白学大数据4 小时前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
qq_390161774 小时前
防抖函数--应用场景及示例
前端·javascript