Skip to content

Commit 0d16903

Browse files
committed
优化find-service实现
1 parent 59cb879 commit 0d16903

File tree

7 files changed

+69
-103
lines changed

7 files changed

+69
-103
lines changed

src/component-container.ts

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/constants.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { type Container, Token } from '@kaokei/di';
22
import type { ComponentInternalInstance } from 'vue';
33
import { createContainer } from './utils';
4+
import type { FindService, FindAllServices } from './interface.ts';
45

56
// 给依赖注入库使用的token
67
export const CURRENT_COMPONENT = new Token<ComponentInternalInstance>(
@@ -12,6 +13,15 @@ export const CURRENT_CONTAINER = new Token<Container>(
1213
'USE_VUE_SERVICE_CURRENT_CONTAINER'
1314
);
1415

16+
// 给依赖注入库使用的token
17+
export const FIND_SERVICE = new Token<FindService>(
18+
'USE_REACT_SERVICE_FIND_SERVICE'
19+
);
20+
// 给依赖注入库使用的token
21+
export const FIND_ALL_SERVICES = new Token<FindAllServices>(
22+
'USE_REACT_SERVICE_FIND_ALL_SERVICES'
23+
);
24+
1525
// 给vue的provide/inject使用的token
1626
export const CONTAINER_TOKEN = 'USE_VUE_SERVICE_CONTAINER_TOKEN';
1727

src/core.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,10 @@ import {
77
App,
88
} from 'vue';
99
import type { Container } from '@kaokei/di';
10-
import type { Newable, CommonToken } from '@kaokei/di';
10+
import type { CommonToken } from '@kaokei/di';
1111
import { createContainer } from './utils';
1212
import { CONTAINER_TOKEN, DEFAULT_CONTAINER } from './constants';
13-
14-
type NewableProvider = Newable[];
15-
type FunctionProvider = (container: Container) => void;
16-
type Provider = NewableProvider | FunctionProvider;
13+
import type { NewableProvider, FunctionProvider, Provider } from './interface';
1714

1815
function bindProviders(container: Container, providers: FunctionProvider): void;
1916
function bindProviders(container: Container, providers: NewableProvider): void;

src/find-service.ts

Lines changed: 14 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,37 @@
1-
import type { CommonToken } from '@kaokei/di';
2-
import type {
3-
VNode,
4-
VNodeChild,
5-
VNodeArrayChildren,
6-
VNodeNormalizedChildren,
7-
ComponentInternalInstance,
8-
} from 'vue';
9-
import { getContainer } from './component-container';
1+
import type { CommonToken, Container } from '@kaokei/di';
102

11-
/**
12-
* useService是从当前组件开始像父组件以及祖先组件查找服务实例
13-
* findService是从当前组件【不包含当前组件】向子组件以及后代组件查找服务实例
14-
* 可以通过component.container尝试获取该组件是否有绑定对应的inversify的container
15-
* 然后通过container.isBound(token)来判断是否有绑定对应的服务
16-
* 如果有绑定则通过container.get(token)来获取服务实例
17-
* 注意component.subTree.children是当前组件的子组件
18-
* 整个过程是一个递归的过程,因为子组件还有子组件,所以需要递归查找
19-
* vnode.children
20-
* vnode.component [node.component.subTree]
21-
* vnode.suspense [node.suspense.activeBranch]
22-
* vnode 判断所有vnode是否符合条件
23-
*/
24-
25-
function nodesAsObject(
26-
value: VNodeChild | VNodeArrayChildren
27-
): value is VNodeArrayChildren | VNode {
28-
return !!value && typeof value === 'object';
29-
}
30-
31-
function walk<T>(vnode: VNode, token: CommonToken<T>, results: T[]): T[] {
32-
if (vnode.component) {
33-
const container = getContainer(vnode.component);
34-
if (container && container.isCurrentBound(token)) {
35-
results.push(container.get(token));
36-
}
37-
}
38-
// 优先遍历当前组件的子组件树
39-
walkChildren(vnode.children, token, results);
40-
if (vnode.component) {
41-
walk(vnode.component.subTree, token, results);
42-
}
43-
if (vnode.suspense && vnode.suspense.activeBranch) {
44-
walk(vnode.suspense.activeBranch, token, results);
45-
}
46-
return results;
47-
}
48-
49-
function walkChildren<T>(
50-
children: VNodeNormalizedChildren,
3+
function walk<T>(
4+
children: Set<Container> | undefined,
515
token: CommonToken<T>,
526
results: T[]
537
): T[] {
54-
if (children && Array.isArray(children)) {
55-
const filteredNodes = children.filter(nodesAsObject);
56-
filteredNodes.forEach((node: VNodeArrayChildren | VNode) => {
57-
/* v8 ignore next 2 */
58-
if (Array.isArray(node)) {
59-
walkChildren(node, token, results);
60-
} else {
61-
walk(node, token, results);
8+
if (children) {
9+
children.forEach(container => {
10+
if (container && container.isCurrentBound(token)) {
11+
results.push(container.get(token));
12+
}
13+
if (container.children) {
14+
walk(container.children, token, results);
6215
}
6316
});
6417
}
6518
return results;
6619
}
6720

68-
/**
69-
* @param component ComponentInternalInstance 当前组件
70-
* @param token CommonToken<T> 服务标识
71-
* @returns T | undefined 是从当前组件【不包含当前组件】的子组件以及后代组件中查找服务实例,返回第一个找到的服务实例
72-
*/
7321
export function findService<T>(
7422
token: CommonToken<T>,
75-
component: ComponentInternalInstance
23+
container: Container
7624
): T | undefined {
7725
const results: T[] = [];
78-
walk(component.subTree, token, results);
26+
walk(container.children, token, results);
7927
return results[0];
8028
}
8129

82-
/**
83-
* @param component ComponentInternalInstance 当前组件
84-
* @param token CommonToken<T> 服务标识
85-
* @returns T[] 是从当前组件【不包含当前组件】的子组件以及后代组件中查找服务实例,返回所有找到的服务实例
86-
*/
8730
export function findAllServices<T>(
8831
token: CommonToken<T>,
89-
component: ComponentInternalInstance
32+
container: Container
9033
): T[] {
9134
const results: T[] = [];
92-
walk(component.subTree, token, results);
35+
walk(container.children, token, results);
9336
return results;
9437
}

src/index.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
export * from '@kaokei/di';
22

3-
export { CURRENT_COMPONENT, CURRENT_CONTAINER } from './constants';
4-
5-
export { findService, findAllServices } from './find-service';
3+
export {
4+
CURRENT_COMPONENT,
5+
CURRENT_CONTAINER,
6+
FIND_SERVICE,
7+
FIND_ALL_SERVICES,
8+
} from './constants';
69

710
export {
811
declareProviders,
@@ -15,3 +18,7 @@ export {
1518
} from './core';
1619

1720
export { Computed } from './computed';
21+
22+
// 不建议业务直接使用
23+
// 建议使用useService(FIND_SERVICE)和useService(FIND_ALL_SERVICES)
24+
export { findService, findAllServices } from './find-service';

src/interface.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import type { Container, Newable, CommonToken } from '@kaokei/di';
2+
3+
export type NewableProvider = Newable[];
4+
export type FunctionProvider = (container: Container) => void;
5+
export type Provider = NewableProvider | FunctionProvider;
6+
7+
export type FindService = <T>(token: CommonToken<T>) => T | undefined;
8+
9+
export type FindAllServices = <T>(token: CommonToken<T>) => T[];

src/utils.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,50 @@
1-
import { Container } from '@kaokei/di';
1+
import { Container, type Context, type CommonToken } from '@kaokei/di';
22
import { reactive, type ComponentInternalInstance, markRaw } from 'vue';
3-
import { setContainer } from './component-container';
4-
import { CURRENT_COMPONENT, CURRENT_CONTAINER } from './constants';
3+
import {
4+
CURRENT_COMPONENT,
5+
CURRENT_CONTAINER,
6+
FIND_SERVICE,
7+
FIND_ALL_SERVICES,
8+
} from './constants';
9+
import { findService, findAllServices } from './find-service.ts';
510

6-
function isObject(val: object) {
11+
export function isObject(val: object) {
712
return val !== null && typeof val === 'object';
813
}
914

1015
function makeReactiveObject(_: any, obj: any) {
1116
return isObject(obj) ? reactive(obj) : obj;
1217
}
1318

19+
function makeFindService({ container }: Context) {
20+
return <T>(token: CommonToken<T>) => findService<T>(token, container);
21+
}
22+
23+
function makeFindAllServices({ container }: Context) {
24+
return <T>(token: CommonToken<T>) => findAllServices<T>(token, container);
25+
}
26+
1427
export function createContainer(
1528
parent?: Container,
1629
instance?: ComponentInternalInstance | null
1730
) {
1831
let container: Container;
32+
1933
if (parent) {
2034
container = parent.createChild();
2135
} else {
2236
container = new Container();
2337
}
38+
2439
if (instance) {
25-
// 组件实例绑定容器-方便后续通过组件实例获取容器对象
26-
// 目前只是提供给findService使用
27-
setContainer(instance, container);
2840
// 容器绑定组件实例-方便后续通过依赖注入获取当前组件实例
2941
container.bind(CURRENT_COMPONENT).toConstantValue(markRaw(instance));
30-
// 容器绑定容器对象-方便后续通过依赖注入获取当前容器对象
31-
container.bind(CURRENT_CONTAINER).toConstantValue(markRaw(container));
3242
}
43+
// 容器绑定容器对象-方便后续通过依赖注入获取当前容器对象
44+
container.bind(CURRENT_CONTAINER).toConstantValue(markRaw(container));
45+
container.bind(FIND_SERVICE).toDynamicValue(makeFindService);
46+
container.bind(FIND_ALL_SERVICES).toDynamicValue(makeFindAllServices);
47+
3348
// 通过onActivation钩子使得所有实例变成响应式对象
3449
container.onActivation(makeReactiveObject);
3550
return container;

0 commit comments

Comments
 (0)