如何在Vue Composition API / Vue 3.0 + TypeScript中从复合函数访问根上下文?

qnakjoqk  于 2023-08-07  发布在  Vue.js
关注(0)|答案(5)|浏览(153)

我想创建一个可重用的 Package 函数,用TypeScript编写,通过一个复合函数触发吐司通知,如Vue 3.0当前规范中定义的:Composition API RFC的数据。
这个例子使用的是BootstrapVue v2.0吐司组件。对于Vue 2,它将通过根上下文中的this.$bvToast Vue组件示例注入来调用

this.$bvToast.toast('Error happened', {
  title: 'Oh no',
  variant: 'danger'
});

字符串
这个类似服务的组合函数看起来很像这样:

// File: @/util/notify.ts
export function useNotify() {
  const notifyError = (title: string, msg: string) => {
    // How to access context.root as in a function component, without passing it to this function?
    context.root.$bvToast.toast(msg, {
      title,
      variant: 'danger'
    });
  };

  return { notifyError};
}

export default useNotify;


它的用法大致如下:

// Use in your functional component:
import { createComponent } from '@vue/composition-api';

import { useNotify} from '@/util/notify';

export default createComponent({
  name: 'MyFailingComponent',
  setup() {
    const { notifyError } = useNotify();

    notifyError('Request error', 'There was an error processing your request, please try again later.');

    return {};
  }
});

jdzmm42g

jdzmm42g1#

还有:

import { getCurrentInstance } from 'vue'  // or from '@vue/composition-api'

字符串
这将从此方法获取调用组件的root上下文。

const root = getCurrentInstance();  // same as ctx.root in component

l3zydbqr

l3zydbqr2#

好吧,我很快就在同一个RFC站点上找到了一个合适的例子。我决定在这里分享我的例子。
RFC网站目前不包括TypeScript中的示例,我想是为了清楚起见。因为这种编写Vue 3.0组件和组合函数的新方法(作为Mixin的替代品)需要一点时间来适应。

回答:在将需要的部分对象解构到组件代码中时,可以直接将上下文对象传递给复合函数。

// File: @/util/notify.ts
// import { SetupContext } from '@vue/composition-api';

export function useNotify({ root }) {
  const notifyError = (title: string, msg: string) => {
    root.$bvToast.toast(msg, {
      title,
      variant: 'danger'
    });
  };

  return { notifyError };
}

export default useNotify;

个字符

同样使用TypeScript类型与复杂对象解构,当传递多个函数参数作为对象时:

// File: @/util/notify.ts
import { SetupContext } from '@vue/composition-api';

export function useNotify({ context, defaultTitle = 'Hey!' }: { context: SetupContext, defaultTitle?: string }) {
  const notifyError = (msg: string, title?: string) => {
    context.root.$bvToast.toast(msg, {
      title: title || defaultTitle,
      variant: 'danger',
    });
  };

  return {
    notifyError,
  };
}

export default useNotify;
// Usage like:
const { notifyError } = useNotify({ context });
// Or
const { notifyError } = useNotify({ context, defaultTitle: 'Hey there' });

的字符串
整洁的语法,做得好的Vue社区!

3htmauhk

3htmauhk3#

您可能最终会将上下文传递给每个组合对象,因为它们的依赖项可能需要上下文本身。
有一种替代解决方案可以提供根示例,而无需将其传递给您拥有的每个组合。这使得它们在组件中的使用更容易一些:
您可以创建一个通用的useRoot组合,并使用Vue的provide/inject特性实现它:

// File: @/components/Root.js
// This is the app root
import useRoot from '@/composables/useRoot'

export default {
  setup(props, context) {
    const { provideRoot } = useRoot()
    provideRoot(context.root)
  }
}
// File: @/composables/useFancyStuff
// This is your composable (no arguments needed!)
import useRoot from '@/composables/useRoot'

export default function useNavigation() {
  const { injectRoot } = useRoot()
  const { $router } = injectRoot() // if you want to use the router

  $router.push('/')
}
// File: @/composables/useRoot
// The implementation
import { provide, inject } from '@vue/composition-api'

const ProviderSymbol = Symbol()

export default function useRoot() {
  const provideRoot = root => provide(ProviderSymbol, root)
  const injectRoot = () => inject(ProviderSymbol)

  return {
    provideRoot,
    injectRoot
  }
}
yzuktlbb

yzuktlbb4#

在我的例子中,我必须访问setupContext才能访问像setup(props, { root }这样的对象。

export default function useContentManagerPostActions() {
  const { emit, setupContext: { root } } = getCurrentInstance()

  ...

  const addPost = async () => {
    try {
      ...
    } catch (error) {
      ...
      root.$bvToast.toast('A new post could not be created.', {
        title: 'Error',
        variant: 'danger',
        solid: false
      })
    }
  }

字符串

wvyml7n5

wvyml7n55#

编辑:此功能仅在NUXT中可用!!!
client-side上,contextwindow.$vm.$root.context上可用

  • 此方法将在SSR上工作!*

相关问题