From 9076d9ce92401bdc47e0bbbc6ed99c18e2ee0ebb Mon Sep 17 00:00:00 2001 From: agileago Date: Fri, 11 Mar 2022 15:18:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E6=A8=A1=E6=9D=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintignore | 1 + example/main.tsx | 4 +-- .../module/basic/hello-world/count.comp.tsx | 13 ++++++++ example/module/basic/hello-world/hello.vue | 31 +++++++++++++++++++ example/router/routes.ts | 2 +- src/di/index.ts | 21 +++++++++++++ src/extends/component.ts | 6 ++-- src/index.ts | 7 ++++- vite.config.ts | 3 +- 9 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 example/module/basic/hello-world/count.comp.tsx create mode 100644 example/module/basic/hello-world/hello.vue diff --git a/.eslintignore b/.eslintignore index f3b0825..7346565 100644 --- a/.eslintignore +++ b/.eslintignore @@ -11,3 +11,4 @@ coverage commitlint.config.js .cz-config.js .prettierrc.js +*.vue diff --git a/example/main.tsx b/example/main.tsx index e45ee87..08435d7 100644 --- a/example/main.tsx +++ b/example/main.tsx @@ -1,5 +1,5 @@ import '@abraham/reflection' -import { Component, Mut, VueComponent } from 'vue3-oop' +import { createCurrentInjector, Mut, VueComponent } from 'vue3-oop' import { createApp } from 'vue' import 'ant-design-vue/dist/antd.css' import { Layout, Menu } from 'ant-design-vue' @@ -7,8 +7,8 @@ import { RouterLink, RouterView } from 'vue-router' import { RouterStartService } from './router' import { routes } from './router/routes' -@Component({ providers: [RouterStartService] }) class App extends VueComponent { + injector = createCurrentInjector([RouterStartService]) @Mut() collapsed = false render() { return ( diff --git a/example/module/basic/hello-world/count.comp.tsx b/example/module/basic/hello-world/count.comp.tsx new file mode 100644 index 0000000..139451a --- /dev/null +++ b/example/module/basic/hello-world/count.comp.tsx @@ -0,0 +1,13 @@ +import { type ComponentProps, VueComponent } from 'vue3-oop' + +interface CountCompProps { + size: 'large' | 'small' +} + +export class CountComp extends VueComponent { + static defaultProps: ComponentProps = ['size'] + + render() { + return
{this.props.size}
+ } +} diff --git a/example/module/basic/hello-world/hello.vue b/example/module/basic/hello-world/hello.vue new file mode 100644 index 0000000..f7711ba --- /dev/null +++ b/example/module/basic/hello-world/hello.vue @@ -0,0 +1,31 @@ + + + + + diff --git a/example/router/routes.ts b/example/router/routes.ts index fde0d1f..936482e 100644 --- a/example/router/routes.ts +++ b/example/router/routes.ts @@ -12,7 +12,7 @@ export const routes: RouteRecordRaw[] = [ children: [ { path: '/basic/hello-world', - component: () => import('../module/basic/hello-world/hello-world.view'), + component: () => import('../module/basic/hello-world/hello.vue'), meta: { title: 'Hello Wolrd', }, diff --git a/src/di/index.ts b/src/di/index.ts index 696937a..61962fb 100644 --- a/src/di/index.ts +++ b/src/di/index.ts @@ -63,6 +63,7 @@ export function resolveComponent(target: { new (...args: []): any }) { // 如果没有使用 injection-js 则不创建注入器 if (!Reflect.getMetadata('annotations', target)) return new target() const parent = inject(InjectorKey, undefined) + // 从缓存中拿到解析过得依赖 let resolveProviders = Reflect.getOwnMetadata( MetadataProviderKey, target @@ -161,3 +162,23 @@ export function getCurrentInjector(): ReflectiveInjector { // @ts-ignore return instance.provides[InjectorKey] || inject(InjectorKey) } +/** 手动创建当前注射器, 只能用在 setup 中 */ +export function createCurrentInjector( + providers: Provider[], + exclude?: Provider[] +): ReflectiveInjector { + let deps = resolveDependencies(providers) + if (exclude?.length) { + deps = deps.filter((k) => exclude?.includes(k)) + } + const resolveProviders = ReflectiveInjector.resolve(deps) + const parent = inject(InjectorKey, undefined) + const injector = ReflectiveInjector.fromResolvedProviders( + resolveProviders, + parent + ) + provide(InjectorKey, injector) + // 实例化 + resolveProviders.forEach((k) => injector.get(k.key.token)) + return injector +} diff --git a/src/extends/component.ts b/src/extends/component.ts index 8c09640..18e8ed8 100644 --- a/src/extends/component.ts +++ b/src/extends/component.ts @@ -6,7 +6,7 @@ import type { VNodeChild, VNodeProps, } from 'vue' -import { getCurrentInstance, provide } from 'vue' +import { getCurrentInstance, markRaw, provide } from 'vue' import { getEmitsFromProps, useCtx, useProps } from '../helper' import type { Hanlder, @@ -86,7 +86,7 @@ export abstract class VueComponent { } /** 渲染函数 */ - abstract render(ctx: ComponentPublicInstance, cache: any[]): VNodeChild + abstract render?(ctx: ComponentPublicInstance, cache: any[]): VNodeChild } // 为了支持es5浏览器 Object.defineProperty(VueComponent, '__vccOpts', { @@ -116,6 +116,8 @@ Object.defineProperty(VueComponent, '__vccOpts', { // eslint-disable-next-line @typescript-eslint/no-unused-vars setup: (props: any, ctx: any) => { const instance = VueComponent.resolveComponent(CompConstructor) + // 支持模板 + if (CompConstructor.__vccOpts__value.render) return markRaw(instance) return instance.render.bind(instance) }, }) diff --git a/src/index.ts b/src/index.ts index 0d7ac03..23af571 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,7 +5,12 @@ export { Computed } from './decorators/computed' export { Link } from './decorators/link' export { Hook } from './decorators/hook' export * from './helper' -export { Component, InjectorKey, getCurrentInjector } from './di' +export { + Component, + InjectorKey, + getCurrentInjector, + createCurrentInjector, +} from './di' export type { ComponentOptions } from './di' export type { ComponentProps, diff --git a/vite.config.ts b/vite.config.ts index 7e4e277..770eb42 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,12 +1,13 @@ import { defineConfig } from 'vite' import vueJsx from '@vue3-oop/plugin-vue-jsx' +import vue from '@vitejs/plugin-vue' export default defineConfig(({ command, mode }) => { return { plugins: command === 'build' ? undefined - : [vueJsx({ enableObjectSlots: false, slotStable: true })], + : [vue(), vueJsx({ enableObjectSlots: false, slotStable: true })], resolve: { alias: [ { find: /^~/, replacement: '' },