1
0
mirror of synced 2026-03-22 18:48:34 +08:00

feat(vue-component, runtime): 使用 app.resolveComponent 获取组件 (#631)

This commit is contained in:
洩氏诹诹子
2024-09-03 21:07:55 +08:00
committed by roymondchen
parent 6e71448158
commit c3bc1035ad
21 changed files with 184 additions and 31 deletions

View File

@@ -57,6 +57,7 @@
},
"devDependencies": {
"@types/node": "^18.19.0",
"@vue/test-utils": "^2.4.6",
"rimraf": "^3.0.2"
}
}

View File

@@ -0,0 +1,67 @@
/*
* Tencent is pleased to support the open source community by making TMagicEditor available.
*
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { inject } from 'vue-demi';
import type Core from '@tmagic/core';
import { toLine } from '@tmagic/utils';
interface UseComponentOptions {
/** 组件类型 */
componentType?: string;
/** App 实例 */
app?: Core;
}
/**
* 通过组件类型在 App 内获取组件
* @param options 若为字符串则为组件类型,若为对象则为参数选项
* @returns 得到的组件,若未找到则返回带 magic-ui- 前缀的组件类型
*/
export function useComponent<Component = any>(options: string | UseComponentOptions = '') {
let componentType: string | undefined;
let app: Core | undefined;
let component: Component | undefined;
if (typeof options === 'string') {
componentType = options;
} else {
({ componentType, app } = options);
}
if (!componentType || componentType === '') {
componentType = 'container';
}
if (!app) {
app = inject('app');
}
component = resolveComponent({ componentType, app });
if (!component && !componentType.startsWith('magic-ui-')) {
componentType = `magic-ui-${toLine(componentType)}`;
component = resolveComponent({ componentType, app });
}
return component ?? componentType;
}
type resolveComponentOptions = Required<Pick<UseComponentOptions, 'componentType'>> & UseComponentOptions;
function resolveComponent<Component = any>({ componentType, app }: resolveComponentOptions): Component | undefined {
return app?.resolveComponent(componentType);
}

View File

@@ -1,3 +1,4 @@
export * from './hooks/use-editor-dsl';
export * from './hooks/use-dsl';
export * from './hooks/use-app';
export { useComponent } from './hooks/use-component';

View File

@@ -0,0 +1,55 @@
import { describe, expect, test } from 'vitest';
import { defineComponent, isVue3, provide } from 'vue-demi';
import { mount } from '@vue/test-utils';
import Core from '@tmagic/core';
import { useComponent } from '../src';
describe('useComponent', () => {
const app = new Core({});
const fooComponent = 'foo-component';
app.registerComponent('foo', fooComponent);
const containerComponent = {};
app.registerComponent('magic-ui-container', containerComponent);
test('string para', () => {
const component = useComponent('foo');
expect(component).toEqual('magic-ui-foo');
});
test('object para and can find component', () => {
const component = useComponent({ componentType: 'foo', app });
expect(component).toEqual(fooComponent);
});
test('without app and can not find component', () => {
const component = useComponent({ componentType: 'foo' });
expect(component).toEqual('magic-ui-foo');
});
test('with magic-ui- componentType and can not find component', () => {
const component = useComponent({ componentType: 'magic-ui-foo', app });
expect(component).toEqual('magic-ui-foo');
});
test.runIf(isVue3)('auto inject and empty para', () => {
const child = defineComponent({
setup() {
const component = useComponent();
expect(component).toEqual(containerComponent);
},
});
const parent = defineComponent({
template: '<child-com></child-com>',
components: { 'child-com': child },
setup() {
provide('app', app);
},
});
const vueApp = mount(parent);
vueApp.unmount();
});
});