Vue 3 组合 API 和对 Vue 实例的访问

Sta*_*lav 17 javascript vue.js vue-component vuejs3 vue-composition-api

main.js我有这样的事情:

import { myUtilFunc} from './helpers';
Object.defineProperty(Vue.prototype, '$myUtilFunc', { value: myUtilFunc });
Run Code Online (Sandbox Code Playgroud)

通过这种方式,我可以访问myUtilFunc整个应用程序this.$myUtilFunc

但是,setup()如果我无法访问 Vue 3中的方法,我该如何实现this

Dan*_*Dan 18

使用provide/inject

提供

const app = createApp(App);
app.provide('someVarName', someVar);  // `Provide` a variable to all components here
Run Code Online (Sandbox Code Playgroud)

注入

// In *any* component
const { inject } = Vue;
...
setup() {
  const someVar = inject('someVarName');   // injecting variable in setup
}
Run Code Online (Sandbox Code Playgroud)

请注意,您不必从应用程序根目录提供,也可以provide从任何组件提供到仅其子组件:

// In *any* component
const { inject } = Vue;
...
setup() {
  const someVar = inject('someVarName');   // injecting variable in setup
}
Run Code Online (Sandbox Code Playgroud)

原答案

[编辑:虽然我在下面的原始答案对context属性仍然有用,但不再推荐使用context.root指南中不再提及并且可能很快会被弃用。]

在 Vue 3 中,setup有一个可选的第二个参数context。您可以通过context.root而不是访问 Vue 实例this

// In *any* component
setup() {
  ...
},
provide() {
  return {
    someVarName: someVar
  }
}
Run Code Online (Sandbox Code Playgroud)

您可以通过context以下方式访问的内容:

context.attrs
context.slots
context.parent
context.root
context.emit
Run Code Online (Sandbox Code Playgroud)


Ale*_*kka 5

虽然丹的答案是正确的,但我想提供评论中提到的已接受答案的替代方案。各有优缺点,大家可以根据自己的需求来选择。

要理解为什么下面的代码有效,重要的是要记住,提供的属性在组件树中是可传递的。即inject('foo')会在每个父级中查找 'foo' 一直到app; 无需在中间包装器中声明任何内容。

所以,我们可以写这样的东西,其中 globalDateFormatter() 只是我们想要在树下的任何组件中使用的示例函数:

主文件

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

const globalDateFormatter = (date) => {
    return '[' + date.toLocaleString() + ']'
}

const app = createApp(App)
app.provide('globalDateFormatter', globalDateFormatter) // <-- define here
app.mount('#app')
Run Code Online (Sandbox Code Playgroud)

然后,在一些DeepDownComponent.vue 中

<template>
  <p> {{ fmt(new Date()) }} </p>
</template>

<script>
import { inject } from 'vue'
export default {
    setup(){
        const fmt = inject('globalDateFormatter', x => x.toString()) 
        //           ^-- use here, optional 2nd parameter is the default
        return {fmt}
    }
}
</script>
Run Code Online (Sandbox Code Playgroud)

很明显,你可以直接导入使用provideinject带有以下签名

provide<T>(key: InjectionKey<T> | string, value: T): void
Run Code Online (Sandbox Code Playgroud)

inject<T>(key: InjectionKey<T> | string, defaultValue: T): T
Run Code Online (Sandbox Code Playgroud)

在您的代码中的任何地方,不必是 app.provide()

你也可以提供值,甚至是全局存储,就像这样,只是不要忘记使用ref()reactive()根据需要。

简而言之,无论何时您更喜欢依赖注入,提供/注入都是您的朋友。