如何从 Vue Composition API / Vue 3.0 + TypeScript 中的组合函数访问根上下文?
How to access root context from a composition function in Vue Composition API / Vue 3.0 + TypeScript?
我想创建一个用 TypeScript 编写的可重用包装函数,用于通过使用 a 组合触发 toast 通知function,如 Vue 3.0 的当前规范中所定义:Composition API RFC.
本例使用的是BootstrapVue v2.0 toast组件。对于 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 {};
}
});
好吧,我很快就在同一个 RFC 站点上找到了一个合适的示例。但决定在这里分享我的例子。
RFC 站点目前不包含 TypeScript 示例,我想是为了清楚起见。由于这种编写 Vue 3.0 组件和组合函数(作为 Mixins 的替代品)的新方式需要一些时间来适应。
回答:在将需要的部分对象解构到组件代码中时,您可以将上下文对象直接传递给组合函数。
// 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;
// Use in your functional component:
import { createComponent, SetupContext } from '@vue/composition-api';
import { useNotify} from '@/util/notify';
export default createComponent({
name: 'MyFailingComponent',
setup(props: any, context: SetupContext) {
const { notifyError } = useNotify(context);
notifyError('Request error', 'There was an error processing your request, please try again later.');
return {};
}
});
同样使用具有复杂对象解构的 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 社区干得好!
您最终可能会将上下文传递给每个可组合项,因为它们的依赖项本身可能需要上下文。
有一种替代解决方案可以提供根实例,而无需将其传递给您拥有的每个可组合项。这使得它们在组件中的使用更容易一些:
您可以创建通用 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
}
}
还有:
import { getCurrentInstance } from 'vue' // or from '@vue/composition-api'
这将从该方法获取调用组件的 root
上下文。
const root = getCurrentInstance(); // same as ctx.root in component
我想创建一个用 TypeScript 编写的可重用包装函数,用于通过使用 a 组合触发 toast 通知function,如 Vue 3.0 的当前规范中所定义:Composition API RFC.
本例使用的是BootstrapVue v2.0 toast组件。对于 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 {};
}
});
好吧,我很快就在同一个 RFC 站点上找到了一个合适的示例。但决定在这里分享我的例子。
RFC 站点目前不包含 TypeScript 示例,我想是为了清楚起见。由于这种编写 Vue 3.0 组件和组合函数(作为 Mixins 的替代品)的新方式需要一些时间来适应。
回答:在将需要的部分对象解构到组件代码中时,您可以将上下文对象直接传递给组合函数。
// 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;
// Use in your functional component:
import { createComponent, SetupContext } from '@vue/composition-api';
import { useNotify} from '@/util/notify';
export default createComponent({
name: 'MyFailingComponent',
setup(props: any, context: SetupContext) {
const { notifyError } = useNotify(context);
notifyError('Request error', 'There was an error processing your request, please try again later.');
return {};
}
});
同样使用具有复杂对象解构的 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 社区干得好!
您最终可能会将上下文传递给每个可组合项,因为它们的依赖项本身可能需要上下文。
有一种替代解决方案可以提供根实例,而无需将其传递给您拥有的每个可组合项。这使得它们在组件中的使用更容易一些:
您可以创建通用 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
}
}
还有:
import { getCurrentInstance } from 'vue' // or from '@vue/composition-api'
这将从该方法获取调用组件的 root
上下文。
const root = getCurrentInstance(); // same as ctx.root in component