Skip to content

Commit da05b43

Browse files
feat: 优化低代码应用核心类,增强应用配置选项和事件管理功能,更新文档注释以提升可读性
1 parent be04f3e commit da05b43

File tree

8 files changed

+631
-155
lines changed

8 files changed

+631
-155
lines changed

packages/core/src/app.ts

Lines changed: 150 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// 核心实例对象, 接收配置, 文件以及node信息\
1+
// 核心实例对象, 接收配置, 文件以及node信息
22
import {
33
Subscribe,
44
webRequest
@@ -22,85 +22,148 @@ import { LowCodeNode } from './node';
2222
import Flexible from './flexible';
2323
import { defaultTransformStyle } from './utils';
2424

25+
/**
26+
* 应用配置选项接口
27+
*/
2528
interface IAppOptionsConfig {
26-
config?: ISchemasRoot;
27-
designWidth?: number;
28-
ua?: string;
29-
curPage?: Id;
30-
platform?: 'mobile' | 'pc';
31-
disabledFlexible?: boolean;
32-
transformStyle?: (style: Record<string, any>) => Record<string, any>;
33-
request?: IRequestFunction;
34-
useMock?: boolean;
29+
config?: ISchemasRoot; // DSL配置数据
30+
designWidth?: number; // 设计稿宽度
31+
ua?: string; // 用户代理字符串
32+
curPage?: Id; // 当前页面ID
33+
platform?: 'mobile' | 'pc'; // 平台类型
34+
disabledFlexible?: boolean; // 是否禁用移动端适配
35+
transformStyle?: (style: Record<string, any>) => Record<string, any>; // 样式转换函数
36+
request?: IRequestFunction; // 自定义请求函数
37+
useMock?: boolean; // 是否使用Mock数据
3538
}
3639

40+
/**
41+
* 低代码应用核心类
42+
* 负责管理整个低代码应用的生命周期、页面切换、组件注册、事件处理等核心功能
43+
*/
3744
export class LowCodeRoot extends Subscribe implements ILowCodeRoot {
45+
/** 环境信息对象,包含设备、浏览器等信息 */
3846
public env: Env = new Env();
39-
public schemasRoot?: ISchemasRoot; // dsl
47+
48+
/** DSL配置根对象 */
49+
public schemasRoot?: ISchemasRoot;
50+
51+
/** 当前页面实例 */
4052
public page?: LowCodePage;
53+
54+
/** 平台类型,默认为移动端 */
4155
public platform = 'mobile';
56+
57+
/** 组件注册表,存储所有注册的组件 */
4258
public components = new Map();
59+
60+
/** 网络请求函数 */
4361
public request?: IRequestFunction;
62+
63+
/** 数据源管理器 */
4464
public dataSourceManager?: DataSourceManager;
65+
66+
/** 是否使用Mock数据 */
4567
public useMock = false;
68+
69+
/** 移动端适配实例 */
4670
private flexible?: Flexible;
71+
72+
/** 样式转换函数 */
4773
public transformStyle: (style: Record<string, any>) => Record<string, any>;
4874

75+
/** 事件映射表,存储所有注册的事件处理函数 */
4976
private eventMap = new Map();
5077

78+
/**
79+
* 构造函数
80+
* @param options 应用配置选项
81+
*/
5182
constructor(options: IAppOptionsConfig) {
5283
super();
5384

85+
// 设置环境信息
5486
this.setEnv(options.ua);
87+
88+
// 设置平台类型
5589
options.platform && (this.platform = options.platform);
90+
91+
// 初始化移动端适配
5692
this.flexible = new Flexible({ designWidth: options.designWidth });
93+
94+
// 设置DSL配置
5795
if (options.config) {
5896
this.setConfig(options.config, options.curPage);
5997
}
98+
99+
// 设置网络请求函数
60100
if (options.request) {
61101
this.request = options.request;
62102
} else if (typeof globalThis.fetch === 'function') {
103+
// 如果浏览器支持fetch,使用默认的webRequest
63104
this.request = webRequest;
64105
}
106+
107+
// 设置样式转换函数
65108
this.transformStyle = options.transformStyle || ((style: Record<string, any>) => defaultTransformStyle(style, this.flexible?.designWidth));
66109
}
67110

111+
/**
112+
* 设置环境信息
113+
* @param ua 用户代理字符串
114+
*/
68115
public setEnv(ua?: string) {
69116
this.env = new Env(ua);
70117
}
71118

72119
/**
73-
* 设置schemas
74-
* @param config ISchemasRoot
120+
* 设置DSL配置
121+
* @param config ISchemasRoot DSL根配置对象
75122
* @param curPage 当前页面id
76123
*/
77124
public setConfig(config: ISchemasRoot, curPage?: Id) {
78125
this.schemasRoot = config;
79126

127+
// 如果没有指定当前页面,默认使用第一个页面
80128
if (!curPage && config.children.length) {
81129
curPage = config.children[0]!.field;
82130
}
83131

132+
// 销毁之前的数据源管理器
84133
if (this.dataSourceManager) {
85134
this.dataSourceManager.destroy();
86135
}
87136

137+
// 清除之前注册的事件
88138
this.removeEvents();
89139

140+
// 创建新的数据源管理器
90141
this.dataSourceManager = createDataSourceManager(this, this.useMock);
91142

143+
// 设置当前页面
92144
this.setPage(curPage || this.page?.data?.field);
93145

146+
// 处理页面描述信息(标题、关键词、描述等)
94147
this.dealDescribe(config);
95148
}
96149

150+
/**
151+
* 处理页面描述信息,设置页面标题和meta标签
152+
* @param config DSL根配置对象
153+
*/
97154
private dealDescribe(config: ISchemasRoot) {
155+
// 确保在浏览器环境中才执行DOM操作
98156
if (globalThis && globalThis.document) {
157+
// 设置页面标题
99158
globalThis.document.title = config.name;
159+
160+
// 清除现有的meta标签
100161
const metaTags = globalThis.document.getElementsByTagName('meta');
101162
while (metaTags.length > 0) {
102163
metaTags[0]?.parentNode?.removeChild(metaTags[0]);
103164
}
165+
166+
// 设置新的meta标签
104167
if (config.description) {
105168
config.description.keywords &&
106169
this.setDescribe(config.description, 'keywords');
@@ -110,9 +173,15 @@ export class LowCodeRoot extends Subscribe implements ILowCodeRoot {
110173
}
111174
}
112175

176+
/**
177+
* 设置页面meta描述信息
178+
* @param describe 描述对象
179+
* @param key 描述类型(keywords 或 description)
180+
*/
113181
private setDescribe(describe: IMetaDes, key: 'keywords' | 'description') {
114182
const header = globalThis.document.getElementsByTagName('head')[0];
115183
if (describe && describe[key].length > 0) {
184+
// 为每个描述项创建meta标签
116185
for (const str of describe[key]) {
117186
const metaTags = globalThis.document.createElement('meta');
118187
metaTags.name = key;
@@ -123,12 +192,16 @@ export class LowCodeRoot extends Subscribe implements ILowCodeRoot {
123192
}
124193

125194
/**
126-
* 设置当前展示页
195+
* 设置当前展示页面
196+
* @param field 页面标识符
127197
*/
128198
public setPage(field?: Id) {
199+
// 查找指定的页面配置
129200
const pageConfig = this.schemasRoot?.children.find(
130201
(page) => page.field === field
131202
);
203+
204+
// 如果找不到页面配置,清空当前页面
132205
if (!pageConfig) {
133206
if (this.page) {
134207
this.page.destroy();
@@ -138,21 +211,25 @@ export class LowCodeRoot extends Subscribe implements ILowCodeRoot {
138211
return;
139212
}
140213

214+
// 如果是同一个页面,不需要重新创建
141215
if (pageConfig === this.page?.data) return;
142216

217+
// 销毁旧页面
143218
if (this.page) {
144219
this.page.destroy();
145220
}
146221

222+
// 创建新页面实例
147223
this.page = new LowCodePage({ config: pageConfig, root: this });
224+
225+
// 触发页面切换事件
148226
super.emit('page-change', this.page);
149-
// this.bindEvents();
150227
}
151228

152229
/**
153-
* 查询页面
154-
* @param id 节点id
155-
* @returns Page | void
230+
* 查询页面实例
231+
* @param field 页面标识符,不传则返回当前页面
232+
* @returns Page实例或undefined
156233
*/
157234
public getPage(field?: Id) {
158235
if (!field) return this.page;
@@ -161,15 +238,25 @@ export class LowCodeRoot extends Subscribe implements ILowCodeRoot {
161238
}
162239
}
163240

241+
/**
242+
* 删除当前页面
243+
*/
164244
public deletePage() {
165245
this.page = undefined;
166246
}
167247

248+
/**
249+
* 设置设计稿宽度
250+
* @param width 设计稿宽度
251+
*/
168252
public setDesignWidth(width: number) {
169253
this.flexible?.setDesignWidth(width);
170254
}
171255

172-
// TODO 增加设备判断
256+
/**
257+
* 判断是否为移动端设备
258+
* @returns boolean
259+
*/
173260
public isH5() {
174261
return (
175262
this.env.isAndroid ||
@@ -181,87 +268,110 @@ export class LowCodeRoot extends Subscribe implements ILowCodeRoot {
181268
);
182269
}
183270

184-
// 设置body字体大小
185-
271+
/**
272+
* 发送事件
273+
* 重写父类的emit方法,支持组件级别的事件命名空间
274+
* @param name 事件名称
275+
* @param args 事件参数
276+
*/
186277
public override emit(name: string, ...args: any[]) {
187278
const [node, ...otherArgs] = args;
188-
// 由于组件可能有很多个, 所以组件事件需要加入id来区分
279+
// 如果第一个参数是节点实例,为事件名添加节点ID前缀以区分不同组件的同名事件
189280
if (node && node instanceof LowCodeNode && node?.data?.field) {
190281
super.emit(`${node.data.field}:${name}`, node, ...otherArgs);
191282
}
192283
super.emit(name, ...args);
193284
}
194285

195-
// 将事件注册为全局事件
196-
// TODO: 目前是将所有的事件(未使用, 已使用)全部注册, 后续会优化此部分逻辑, 只注册已使用到的, 优化性能
286+
/**
287+
* 注册全局事件
288+
* 将事件函数包装后注册到事件系统中
289+
* @param key 事件键名
290+
* @param fn 事件处理函数
291+
* @param ds 数据源实例
292+
* @param node 节点实例(可选,用于组件事件)
293+
*/
197294
public registerEvent(
198295
key: string,
199296
fn: Fn,
200297
ds?: DataSource,
201298
node?: LowCodeNode
202299
) {
300+
// 包装事件处理函数,注入app和dataSource参数
203301
const eventHanlder = (...args: any[]) => {
204302
fn({ app: this, dataSource: ds || {} }, ...args);
205303
};
206-
// 先清空
304+
305+
// 如果事件已存在,先移除旧的
207306
if (this.cache.has(key)) {
208307
this.remove(key);
209308
}
309+
310+
// 如果是组件事件,添加组件ID前缀
210311
if (node) {
211-
// 组件事件
212312
key = `${node.data.field}:${key}`;
213313
}
314+
315+
// 存储事件处理函数并注册
214316
this.eventMap.set(key, eventHanlder);
215317
this.on(key, eventHanlder);
216318
}
217319

218-
// public async dataSourceActionHandler() {
219-
// }
220-
221320
/**
222-
* 移除所有事件
321+
* 移除所有注册的事件
223322
*/
224323
public removeEvents() {
225-
// 先移除所有事件
324+
// 遍历所有注册的事件并移除
226325
Array.from(this.eventMap.keys()).forEach((key) => {
227326
const events = this.eventMap.get(key);
228327
events && this.remove(key);
229328
});
329+
330+
// 清空事件映射表
230331
this.eventMap.clear();
231332

232333
if (!this.page) return;
233334
}
234-
/**
235-
* 事件联动处理函数
236-
*/
237-
// private async eventHandler() {
238-
239-
// }
240335

241336
/**
242337
* 注册组件
338+
* @param type 组件类型名称
339+
* @param comp 组件实例或组件类
243340
*/
244341
public registerComponent(type: string, comp: any) {
245342
this.components.set(type, comp);
246343
}
247344

248345
/**
249-
* 删除组件
346+
* 注销组件
347+
* @param type 组件类型名称
250348
*/
251349
public unregisterComponent(type: string) {
252350
this.components.delete(type);
253351
}
254352

353+
/**
354+
* 解析获取组件
355+
* @param type 组件类型名称
356+
* @returns 组件实例或组件类
357+
*/
255358
public resolveComponent(type: string) {
256359
return this.components.get(type);
257360
}
258361

362+
/**
363+
* 销毁应用实例
364+
* 清理所有资源,包括事件、页面、适配器等
365+
*/
259366
public destroy() {
367+
// 清理事件订阅
260368
this.clear();
369+
370+
// 清理页面实例
261371
this.page = undefined;
372+
373+
// 销毁移动端适配器
262374
this.flexible?.destroy();
263375
this.flexible = undefined;
264-
// if (this.isH5()) {
265-
// }
266376
}
267377
}

0 commit comments

Comments
 (0)