@oinone/kunlun-vue-widget 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/oinone-kunlun-vue-widget.esm.js +16 -0
  2. package/dist/types/index.d.ts +1 -0
  3. package/dist/types/src/basic/AsyncVueWidget.d.ts +7 -0
  4. package/dist/types/src/basic/VueFragment.vue.d.ts +2 -0
  5. package/dist/types/src/basic/VueWidget.d.ts +331 -0
  6. package/dist/types/src/basic/Widget.d.ts +234 -0
  7. package/dist/types/src/basic/index.d.ts +3 -0
  8. package/dist/types/src/data/ActiveRecordsWidget.d.ts +246 -0
  9. package/dist/types/src/data/PathWidget.d.ts +34 -0
  10. package/dist/types/src/data/index.d.ts +2 -0
  11. package/dist/types/src/dsl/DslDefinitionWidget.d.ts +61 -0
  12. package/dist/types/src/dsl/DslNodeWidget.d.ts +42 -0
  13. package/dist/types/src/dsl/DslRenderWidget.d.ts +44 -0
  14. package/dist/types/src/dsl/index.d.ts +3 -0
  15. package/dist/types/src/feature/index.d.ts +1 -0
  16. package/dist/types/src/feature/invisible-supported.d.ts +11 -0
  17. package/dist/types/src/hooks/all-mounted.d.ts +20 -0
  18. package/dist/types/src/hooks/index.d.ts +1 -0
  19. package/dist/types/src/index.d.ts +9 -0
  20. package/dist/types/src/token/index.d.ts +2 -0
  21. package/dist/types/src/typing/WidgetTagContext.d.ts +39 -0
  22. package/dist/types/src/typing/WidgetTagProps.d.ts +23 -0
  23. package/dist/types/src/typing/index.d.ts +3 -0
  24. package/dist/types/src/typing/typing.d.ts +7 -0
  25. package/dist/types/src/util/dsl-render.d.ts +106 -0
  26. package/dist/types/src/util/index.d.ts +4 -0
  27. package/dist/types/src/util/install.d.ts +4 -0
  28. package/dist/types/src/util/render.d.ts +7 -0
  29. package/dist/types/src/util/widget-manager.d.ts +4 -0
  30. package/dist/types/src/view/index.d.ts +161 -0
  31. package/index.ts +1 -0
  32. package/package.json +34 -0
  33. package/rollup.config.js +21 -0
  34. package/src/basic/AsyncVueWidget.ts +31 -0
  35. package/src/basic/VueFragment.vue +11 -0
  36. package/src/basic/VueWidget.ts +997 -0
  37. package/src/basic/Widget.ts +675 -0
  38. package/src/basic/index.ts +3 -0
  39. package/src/data/ActiveRecordsWidget.ts +572 -0
  40. package/src/data/PathWidget.ts +82 -0
  41. package/src/data/index.ts +2 -0
  42. package/src/dsl/DslDefinitionWidget.ts +235 -0
  43. package/src/dsl/DslNodeWidget.ts +130 -0
  44. package/src/dsl/DslRenderWidget.ts +106 -0
  45. package/src/dsl/index.ts +3 -0
  46. package/src/feature/index.ts +1 -0
  47. package/src/feature/invisible-supported.ts +29 -0
  48. package/src/hooks/all-mounted.ts +179 -0
  49. package/src/hooks/index.ts +1 -0
  50. package/src/index.ts +9 -0
  51. package/src/shim-translate.d.ts +7 -0
  52. package/src/shim-vue.d.ts +6 -0
  53. package/src/token/index.ts +8 -0
  54. package/src/typing/WidgetTagContext.ts +53 -0
  55. package/src/typing/WidgetTagProps.ts +24 -0
  56. package/src/typing/index.ts +3 -0
  57. package/src/typing/typing.ts +7 -0
  58. package/src/util/dsl-render.ts +464 -0
  59. package/src/util/index.ts +4 -0
  60. package/src/util/install.ts +29 -0
  61. package/src/util/render.ts +21 -0
  62. package/src/util/widget-manager.ts +14 -0
  63. package/src/view/index.ts +416 -0
@@ -0,0 +1,997 @@
1
+ import { genStaticPath, translateValueByKey, WidgetConstructor, WidgetProps } from '@oinone/kunlun-engine';
2
+ import { ReturnPromise, uniqueKeyGenerator } from '@oinone/kunlun-shared';
3
+ import { ComponentPublicInstance, SetupContext } from '@vue/runtime-core';
4
+ import {
5
+ Component,
6
+ ComponentOptions,
7
+ computed,
8
+ createVNode,
9
+ defineComponent,
10
+ DefineComponent,
11
+ EffectScope,
12
+ effectScope,
13
+ isRef,
14
+ nextTick,
15
+ ref,
16
+ Ref,
17
+ Slot,
18
+ Slots,
19
+ toRaw,
20
+ VNode,
21
+ watch
22
+ } from 'vue';
23
+ import VueFragment from './VueFragment.vue';
24
+ import { Widget } from './Widget';
25
+
26
+ enum BehaviorName {
27
+ 'beforeCreated' = 'beforeCreated',
28
+ 'created' = 'created',
29
+ 'beforeMount' = 'beforeMount',
30
+ 'mounted' = 'mounted',
31
+ 'beforeUpdate' = 'beforeUpdate',
32
+ 'updated' = 'updated',
33
+ 'activated' = 'activated',
34
+ 'deactivated' = 'deactivated',
35
+ 'beforeUnmount' = 'beforeUnmount',
36
+ 'unmounted' = 'unmounted'
37
+ }
38
+
39
+ export type WidgetComponent = string | ComponentOptions | DefineComponent | Component | Record<string, unknown>;
40
+
41
+ export type SetupHook =
42
+ | ((ctx?: void, props?: unknown, result?: unknown) => void)
43
+ | ((ctx?: void, props?: unknown, result?: unknown) => unknown)
44
+ | ((ctx?: void, props?: unknown, result?: unknown) => Promise<void>)
45
+ | ((ctx?: void, props?: unknown, result?: unknown) => Promise<unknown>);
46
+
47
+ export class VueWidget<Props extends WidgetProps = WidgetProps> extends Widget<Props, VNode | VNode[]> {
48
+ protected behaviorGroup = {};
49
+
50
+ private __render__?: (...args: unknown[]) => VNode | null;
51
+
52
+ private static beforeHooks: Map<
53
+ string,
54
+ Map<string, ((next: (args: unknown[]) => void, ...args: unknown[]) => boolean | undefined)[]>
55
+ > = new Map();
56
+
57
+ private static afterHooks: Map<
58
+ string,
59
+ Map<string, ((next: (result: unknown) => void, ...args: unknown[]) => boolean | undefined)[]>
60
+ > = new Map();
61
+
62
+ private static hookHosts: Map<Function, string[]> = new Map();
63
+
64
+ /**
65
+ * 通过该属性可以直接拿到Widget下Component内的属性
66
+ * @private
67
+ */
68
+ private opt?: VueWidget;
69
+
70
+ /**
71
+ * vue实例内属性(props、computed、data)的集合
72
+ */
73
+ private res?: {};
74
+
75
+ public revolveNodeCode() {
76
+ return uniqueKeyGenerator();
77
+ }
78
+
79
+ private __scope!: EffectScope | null;
80
+
81
+ /**
82
+ * vue组件setup
83
+ * @param setupHook
84
+ */
85
+ public setup(setupHook?: SetupHook) {
86
+ return (ctx: void, props?: unknown) => {
87
+ if (this.__scope) {
88
+ this.__scope.stop();
89
+ this.__scope = null;
90
+ }
91
+
92
+ this.__scope = effectScope();
93
+ let result = {};
94
+
95
+ this.__scope.run(() => {
96
+ const { opt } = this;
97
+ const attrs = this.getAttributes();
98
+ attrs.forEach((nativeName, displayName) => {
99
+ const compute = this.getComputeHandler(displayName);
100
+ if (compute) {
101
+ if (compute.get) {
102
+ if (!compute.set) {
103
+ Reflect.set(result, displayName, computed(compute.get!.bind(opt)));
104
+ } else {
105
+ Reflect.set(
106
+ result,
107
+ displayName,
108
+ computed({
109
+ get: compute.get!.bind(opt),
110
+ set: compute.set!.bind(opt)
111
+ })
112
+ );
113
+ }
114
+ }
115
+ } else {
116
+ const raw = Reflect.get(this, nativeName);
117
+ if (typeof raw === 'function') {
118
+ Reflect.set(result, displayName, raw.bind(opt));
119
+ } else if (typeof raw === 'object' && raw) {
120
+ Reflect.set(result, displayName, ref(raw));
121
+ } else {
122
+ Reflect.set(result, displayName, ref(raw));
123
+ }
124
+ }
125
+ });
126
+
127
+ const watchers = this.getWatchers();
128
+ watchers.forEach((watcher) => {
129
+ const path = watcher.path.split('.');
130
+ const val = result[path[0]];
131
+ if (val) {
132
+ if (path.length === 1) {
133
+ /**
134
+ *如果当前要监听的值是个Object类型,那么监听的newValue跟oldValue是相等的
135
+ *
136
+ * @see {@link https://cn.vuejs.org/v2/api/#vm-watch}
137
+ */
138
+ watch(val, watcher.handler.bind(opt), watcher.options);
139
+ } else {
140
+ watch(
141
+ () => {
142
+ let tmp = val.value || {};
143
+ for (let index = 1; index < path.length; index++) {
144
+ tmp = tmp[path[index]];
145
+ if (!tmp) {
146
+ break;
147
+ }
148
+ }
149
+ return tmp;
150
+ },
151
+ watcher.handler.bind(opt),
152
+ watcher.options
153
+ );
154
+ }
155
+ }
156
+ });
157
+ const returnResult = setupHook && (setupHook(ctx, props, result) as Record<string, unknown>);
158
+ returnResult && (result = { ...result, ...returnResult });
159
+ this.res = result;
160
+ });
161
+
162
+ return result;
163
+ };
164
+ }
165
+
166
+ /**
167
+ * 标记一个方法为可被钩子注入,注解使用
168
+ * @constructor
169
+ * @protected
170
+ */
171
+ protected static HookHost() {
172
+ return <T extends Widget>(target: T, name: string) => {
173
+ const hosts: string[] = VueWidget.hookHosts.get(target.constructor) || [];
174
+ hosts.push(name);
175
+ VueWidget.hookHosts.set(target.constructor, hosts);
176
+ };
177
+ }
178
+
179
+ /**
180
+ * 获得组件中注册的所有钩子
181
+ * @param widget
182
+ * @private
183
+ */
184
+ private static getHookHosts(widget: Widget) {
185
+ const results: string[] = [];
186
+
187
+ /**
188
+ * 获得对象的继承链
189
+ * 0: ColorPickWidget()
190
+ * 1: FormFieldWidget()
191
+ * 2: FieldWidget()
192
+ * 3: DslNodeWidget()
193
+ * 4: VueWidget()
194
+ * 5: Widget()
195
+ */
196
+ const getProtoChains = (): Function[] => {
197
+ const chains: Function[] = [];
198
+ let obj = widget.constructor;
199
+ let { name } = obj;
200
+ while (name !== '') {
201
+ name = obj.name;
202
+ chains.push(obj);
203
+ obj = Object.getPrototypeOf(obj);
204
+ }
205
+ return chains;
206
+ };
207
+ const chains = getProtoChains();
208
+ chains.forEach((c) => {
209
+ const hosts = VueWidget.hookHosts.get(c);
210
+ hosts && hosts.forEach((r) => results.push(r));
211
+ });
212
+ return results;
213
+ }
214
+
215
+ /**
216
+ * 获得指定组件内方法的前/后置钩子
217
+ * @param widgetName
218
+ * @param hook
219
+ * @param beforeOrAfter
220
+ * @private
221
+ */
222
+ private static getHooks(widgetName: string, hook: string, beforeOrAfter: 'before' | 'after') {
223
+ const widget = Widget.select(widgetName)!;
224
+ const getProtoChains = <T extends Function>(obj: T) => {
225
+ const result: string[] = [];
226
+ let iterator = obj;
227
+ while (iterator.name !== '') {
228
+ result.push(iterator.name);
229
+ iterator = Object.getPrototypeOf(iterator);
230
+ }
231
+ return result;
232
+ };
233
+ const chains = getProtoChains(widget.constructor);
234
+ const hooks: ((
235
+ next: (...args: unknown[]) => void,
236
+ ...args: unknown[]
237
+ ) => boolean | undefined | Promise<boolean> | Promise<void>)[] = [];
238
+ chains.forEach((c) => {
239
+ let tahooks: Map<
240
+ string,
241
+ ((
242
+ next: (...args: unknown[]) => void,
243
+ ...args: unknown[]
244
+ ) => boolean | undefined | Promise<boolean> | Promise<void>)[]
245
+ >;
246
+ if (beforeOrAfter === 'after') {
247
+ tahooks = VueWidget.afterHooks.get(c)!;
248
+ } else {
249
+ tahooks = VueWidget.beforeHooks.get(c)!;
250
+ }
251
+ const thooks = (tahooks && tahooks.get(hook)) || [];
252
+ thooks.forEach((hookHandle) => hooks.push(hookHandle));
253
+ });
254
+ return hooks;
255
+ }
256
+
257
+ /**
258
+ * 标记一个方法为后置钩子
259
+ * @param host
260
+ * @constructor
261
+ * @protected
262
+ */
263
+ protected static BeforeHook(host: string) {
264
+ return <T extends Widget>(
265
+ target: T,
266
+ _name: string,
267
+ description: TypedPropertyDescriptor<() => boolean> | TypedPropertyDescriptor<() => void>
268
+ ) => {
269
+ const afterHosts = VueWidget.beforeHooks.get(target.constructor.name) || new Map();
270
+ const afterHooks = afterHosts.get(host) || [];
271
+ afterHooks.push(description.value!);
272
+ afterHosts.set(host, afterHooks);
273
+ VueWidget.beforeHooks.set(target.constructor.name, afterHosts);
274
+ };
275
+ }
276
+
277
+ /**
278
+ * 标记一个方法为前置钩子
279
+ * @param host
280
+ * @constructor
281
+ * @protected
282
+ */
283
+ protected static AfterHook(host: string) {
284
+ return <T extends Widget>(
285
+ target: T,
286
+ _name: string,
287
+ description:
288
+ | TypedPropertyDescriptor<(next: never, ...args: unknown[]) => boolean>
289
+ | TypedPropertyDescriptor<(next: unknown, ...args: unknown[]) => void>
290
+ ) => {
291
+ const afterHosts = VueWidget.afterHooks.get(target.constructor.name) || new Map();
292
+ const afterHooks = afterHosts.get(host) || [];
293
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
294
+ afterHooks.push(description.value!);
295
+ afterHosts.set(host, afterHooks);
296
+ VueWidget.afterHooks.set(target.constructor.name, afterHosts);
297
+ };
298
+ }
299
+
300
+ private component!: WidgetComponent;
301
+
302
+ @Widget.Reactive()
303
+ private node_code: string = this.revolveNodeCode();
304
+
305
+ public getNodeCode(): string {
306
+ return this.node_code;
307
+ }
308
+
309
+ public getNodeCodeRef(): Ref<number> {
310
+ return (this.res! as { node_code: Ref<number> }).node_code;
311
+ }
312
+
313
+ /**
314
+ * 获取当前组件的响应式对象
315
+ */
316
+ public getOperator<T extends VueWidget>(): T {
317
+ const { opt } = this;
318
+ if (!opt) {
319
+ return this as unknown as T;
320
+ // throw new Error(`error: operator lost :${this.getWidgetType()}:${this.getHandle()}`);
321
+ }
322
+ return opt as T;
323
+ }
324
+
325
+ /**
326
+ * 在当前组件节点下创建子节点
327
+ * @param constructor widget
328
+ * @param slotName slotName
329
+ * @param initConfig widget中initialize函数接受的参数
330
+ * @param specifiedIndex 指定该widget的在父节点中的位置,默认是最后一位
331
+ * @param resolveNewCode 是否更新node_code
332
+ */
333
+ public createWidget<T extends Widget>(
334
+ constructor: WidgetConstructor<T['config'], T>,
335
+ slotName?: string,
336
+ initConfig?: T['config'],
337
+ specifiedIndex?: number,
338
+ resolveNewCode = false
339
+ ): T {
340
+ const opt = this.getOperator();
341
+ const widget: T = super.createWidget.bind(opt)<T>(
342
+ constructor,
343
+ slotName,
344
+ initConfig || ({} as T['config']),
345
+ specifiedIndex
346
+ );
347
+ // 不要改,兼容执行视图和mask重新渲染 拿掉if mask的重绘失效了
348
+ if (resolveNewCode) {
349
+ opt.node_code = this.revolveNodeCode();
350
+ }
351
+ const instance = widget && widget.getOperator();
352
+ if (specifiedIndex !== undefined && specifiedIndex >= 0) {
353
+ this.getChildrenInstance()[specifiedIndex] = widget.getOperator();
354
+ } else {
355
+ // fixme: widget可能为空
356
+ this.addChildrenInstance(instance);
357
+ }
358
+ return instance as unknown as T;
359
+ }
360
+
361
+ /**
362
+ * 在当前组件节点下删除子节点树
363
+ * @param name
364
+ */
365
+ public deleteWidget(name: string) {
366
+ const result = super.deleteWidget(name);
367
+ const opt = this.getOperator();
368
+ opt.node_code = this.revolveNodeCode();
369
+
370
+ return result;
371
+ }
372
+
373
+ /**
374
+ * 给指定的下标插入widget
375
+ *
376
+ * 如果要在最后一位插入,可以用createWidget
377
+ *
378
+ * @param {Widget} widget
379
+ * @param {number} index
380
+ */
381
+ public insertWidget(widget: Widget, index: number) {
382
+ super.insertWidget(widget, index);
383
+ const opt = this.getOperator();
384
+ opt.node_code = this.revolveNodeCode();
385
+ }
386
+
387
+ /**
388
+ * 移动widget, 将widget从 A 下标移动到 B 下标
389
+ *
390
+ * @param {number} index1
391
+ * @param {number} index2
392
+ */
393
+ public moveChildWidget(index1: number, index2: number) {
394
+ super.moveChildWidget(index1, index2);
395
+ const opt = this.getOperator();
396
+ opt.node_code = this.revolveNodeCode();
397
+ }
398
+
399
+ /**
400
+ * 根据下标删除对应的child widget, 如果当前 children中有重复的handler,那么会删除匹配的第一个
401
+ *
402
+ * @param {number} index
403
+ * @param {string} handle?
404
+ */
405
+ public deleteWidgetByIndex(index: number, handle?: string) {
406
+ const result = super.deleteWidgetByIndex(index, handle);
407
+ const opt = this.getOperator();
408
+ opt.node_code = this.revolveNodeCode();
409
+
410
+ return result;
411
+ }
412
+
413
+ /**
414
+ * 初始化当前组件
415
+ * @param props
416
+ */
417
+ public initialize(props: Props = {} as Props): VueWidget {
418
+ super.initialize(props);
419
+ this.component = VueFragment;
420
+ this.buildOperator();
421
+ /* IFDEBUG */
422
+ // console.debug(`${this.getWidgetType()}:initialize`);
423
+ /* FIDEBUG */
424
+ return this;
425
+ }
426
+
427
+ private buildOperator(): VueWidget {
428
+ const operator = new Proxy(this, {
429
+ get: (target, key: string | symbol) => {
430
+ if (key === 'isProxy') {
431
+ return true;
432
+ }
433
+ if (key === 'constructor') {
434
+ return this.constructor;
435
+ }
436
+ const result = this.res || {};
437
+ const res = Reflect.get(result, key);
438
+ if (res) {
439
+ if (isRef(res)) {
440
+ if (typeof res.value === 'object') {
441
+ return res.value;
442
+ }
443
+ return res.value;
444
+ }
445
+ return res;
446
+ }
447
+ return Reflect.get(target, key);
448
+ },
449
+ set: (target, key: string | symbol, value: unknown) => {
450
+ const result = this.res || {};
451
+ const res = Reflect.get(result, key);
452
+ if (typeof res === 'function') {
453
+ return Reflect.set(result, key, value);
454
+ }
455
+ if (isRef(res)) {
456
+ res.value = value;
457
+ return true;
458
+ }
459
+ return Reflect.set(target, key, value);
460
+ }
461
+ });
462
+ this.opt = operator;
463
+ this.initialize = this.initialize.bind(operator);
464
+
465
+ const hosts = VueWidget.getHookHosts(this);
466
+ hosts.forEach((hookName) => {
467
+ const host = Reflect.get(this, hookName);
468
+ Reflect.set(this, hookName, (...args: unknown[]) => {
469
+ if (hookName === 'render') {
470
+ return host.apply(operator, args);
471
+ }
472
+ const _args = operator.executeBeforeHooks(hookName, args);
473
+ const result = host.apply(operator, _args);
474
+ return operator.executeAfterHooks(hookName, result);
475
+ });
476
+ });
477
+ return operator;
478
+ }
479
+
480
+ /**
481
+ * Class Component Vue组件
482
+ * @private
483
+ */
484
+ private widgetComponent: Component | undefined;
485
+
486
+ /**
487
+ * 获取Class Component Vue组件
488
+ */
489
+ public getWidgetComponent(isBuild = false): Component | undefined {
490
+ let component = this.widgetComponent;
491
+ if (!component && isBuild) {
492
+ component = this.buildWidgetComponent();
493
+ this.widgetComponent = component;
494
+ }
495
+ return component;
496
+ }
497
+
498
+ /**
499
+ * 设置Class Component Vue组件
500
+ * @param component Vue组件
501
+ */
502
+ public setWidgetComponent(component: Component | undefined) {
503
+ this.widgetComponent = component;
504
+ }
505
+
506
+ /**
507
+ * 扩展组件
508
+ */
509
+ public renderExpandComponent(): Component | VNode | undefined {
510
+ return undefined;
511
+ }
512
+
513
+ /**
514
+ * 混入组件
515
+ * @private
516
+ */
517
+ private mixinComponent: Component | undefined;
518
+
519
+ /**
520
+ * 获取混入组件
521
+ */
522
+ public getMixinComponent() {
523
+ return this.mixinComponent;
524
+ }
525
+
526
+ /**
527
+ * 设置混入组件
528
+ * @param component Vue组件
529
+ * @protected
530
+ */
531
+ public setMixinComponent(component: Component | undefined) {
532
+ if (component) {
533
+ component = {
534
+ inheritAttrs: false,
535
+ ...component
536
+ };
537
+ }
538
+ this.mixinComponent = component;
539
+ }
540
+
541
+ /**
542
+ * 渲染当前组件
543
+ * @param context 渲染上下文
544
+ * @param slots 插槽
545
+ */
546
+ @VueWidget.HookHost()
547
+ public render(context?: Record<string, unknown>, slots?: Slots): VNode | VNode[] {
548
+ if (!this.widgetComponent) {
549
+ this.widgetComponent = this.buildWidgetComponent();
550
+ }
551
+ if (!this.widgetComponent) {
552
+ return [];
553
+ }
554
+ return this.renderWidgetComponent(this.widgetComponent, context, slots);
555
+ }
556
+
557
+ protected getWidgetComponentName() {
558
+ const { name } = this.constructor;
559
+ return name;
560
+ }
561
+
562
+ /**
563
+ * 构造Vue组件
564
+ * @protected
565
+ */
566
+ protected buildWidgetComponent(): Component | undefined {
567
+ let component = this.getComponent();
568
+ if (!component) {
569
+ return undefined;
570
+ }
571
+ component = toRaw(component);
572
+ // const setup: any = this.setup(this.setupHook.bind(this));
573
+
574
+ const opt = this.getOperator();
575
+ const extendComponents = this.getUsingComponents();
576
+ return defineComponent({
577
+ name: this.getWidgetComponentName(),
578
+ components: extendComponents,
579
+ inheritAttrs: false,
580
+ setup: this.setup(this.setupHook.bind(this)) as any,
581
+ beforeMount: () => {
582
+ this.behaviorGroup[BehaviorName.beforeMount]?.();
583
+ this.$$beforeMount.call(opt);
584
+ this.beforeMount.call(opt);
585
+ },
586
+ mounted: () => {
587
+ this.behaviorGroup[BehaviorName.mounted]?.();
588
+ this.$$mounted.call(opt);
589
+ this.mounted.call(opt);
590
+ },
591
+ beforeUpdate: () => {
592
+ this.behaviorGroup[BehaviorName.beforeUpdate]?.();
593
+ this.$$beforeUpdate.call(opt);
594
+ this.beforeUpdate.call(opt);
595
+ },
596
+ updated: () => {
597
+ this.behaviorGroup[BehaviorName.updated]?.();
598
+ this.$$updated.call(opt);
599
+ this.updated.call(opt);
600
+ },
601
+ activated: () => {
602
+ this.behaviorGroup[BehaviorName.activated]?.();
603
+ this.$$activated.call(opt);
604
+ this.activated.call(opt);
605
+ },
606
+ deactivated: () => {
607
+ this.behaviorGroup[BehaviorName.deactivated]?.();
608
+ this.$$deactivated.call(opt);
609
+ this.deactivated.call(opt);
610
+ },
611
+ beforeUnmount: () => {
612
+ this.behaviorGroup[BehaviorName.beforeUnmount]?.();
613
+ this.$$beforeUnmount.call(opt);
614
+ this.beforeUnmount.call(opt);
615
+ },
616
+ unmounted: () => {
617
+ this.behaviorGroup[BehaviorName.unmounted]?.();
618
+ this.unmounted.call(opt);
619
+ this.$$unmounted.call(opt);
620
+ this.$$unmountedAfterProperties.call(opt);
621
+ },
622
+ render: (ctx: ComponentPublicInstance & Record<string, unknown>) => {
623
+ const props = this.buildProps(ctx);
624
+ const { $slots } = ctx;
625
+ const componentProps = this.resolveProps(component, props);
626
+
627
+ const children = $slots && Object.keys($slots).length ? $slots : this.resolveChildren();
628
+
629
+ const expandCom = this.renderExpandComponent() as VNode;
630
+ const expandSlot = {} as Record<string, any>;
631
+
632
+ if (expandCom) {
633
+ const defaultSlotContent = children.default ? children.default() : [];
634
+ expandSlot.default = () => [...defaultSlotContent, expandCom];
635
+ }
636
+
637
+ return this.renderMixinComponent(
638
+ createVNode(component, componentProps, {
639
+ ...children,
640
+ ...expandSlot
641
+ }),
642
+ props
643
+ );
644
+ }
645
+ });
646
+ }
647
+
648
+ /**
649
+ * 只获取vue 组件需要的props
650
+ *
651
+ */
652
+ protected resolveProps(component, props) {
653
+ return props;
654
+ // TODO 由于很多组件内部使用了$attrs, 需要先把$attrs替换成对应的props,再使用下面的代码,性能可提升20%
655
+ // const componentProps = (component as VNode).props || {};
656
+ // const keys = Array.isArray(componentProps) ? componentProps : Object.keys(componentProps);
657
+
658
+ // if (component.mixins && component.mixins.length) {
659
+ // keys.push(...component.mixins.map((mixin) => Object.keys(mixin.props || {})));
660
+ // }
661
+
662
+ // return keys.reduce((acc, key) => ({ ...acc, [key]: props[key] }), {});
663
+ }
664
+
665
+ /**
666
+ * 渲染混入组件
667
+ * @param vNode 当前Vue组件渲染节点
668
+ * @param props 当前Vue组件渲染属性
669
+ * @protected
670
+ */
671
+ protected renderMixinComponent(vNode: VNode, props: Record<string, unknown>): VNode | VNode[] {
672
+ const mixinComponent = this.getMixinComponent();
673
+ if (mixinComponent) {
674
+ const finalVNode = vNode;
675
+ const realProps = this.resolveProps(mixinComponent, props);
676
+ vNode = createVNode(mixinComponent, realProps, { default: () => finalVNode });
677
+ }
678
+ return vNode;
679
+ }
680
+
681
+ /**
682
+ * 渲染当前组件
683
+ * @param widgetComponent 当前组件
684
+ * @param context 组件上下文
685
+ * @param slots 组件插槽
686
+ * @protected
687
+ */
688
+ protected renderWidgetComponent(widgetComponent: Component, context?: Record<string, unknown>, slots?: Slots): VNode {
689
+ return createVNode(widgetComponent, {}, slots);
690
+ }
691
+
692
+ /**
693
+ * 构建当前组件渲染vue组件传递时的props
694
+ * @param result
695
+ * @protected
696
+ */
697
+ protected buildProps(result: Record<string, unknown>) {
698
+ const props: Record<string, unknown> = {};
699
+
700
+ const attrs = this.getAttributes();
701
+
702
+ const propStrs = this.getProps();
703
+ attrs.forEach((displayName, nativeName) => {
704
+ if (propStrs.includes(displayName)) {
705
+ Reflect.set(props, displayName, Reflect.get(result, nativeName));
706
+ }
707
+ });
708
+ props['data-handle'] = this.getHandle();
709
+ return props;
710
+ }
711
+
712
+ protected buildPropsStrs(): string[] {
713
+ const attrs = this.getProps();
714
+ const props: string[] = [];
715
+ attrs.forEach((key) => props.push(key));
716
+ return props;
717
+ }
718
+
719
+ /**
720
+ * 将当前组件的子组件树解析为Vue Slots树
721
+ * @protected
722
+ */
723
+ protected resolveChildren(): Record<string, Slot> {
724
+ const result = {};
725
+ const slots: string[] = [];
726
+ const children = this.getChildren();
727
+ children.forEach((c) => {
728
+ if (!slots.includes(c.getName())) {
729
+ slots.push(c.getName());
730
+ }
731
+ });
732
+ slots.forEach((s) => {
733
+ Reflect.set(result, s, (...args: unknown[]) =>
734
+ children.filter((c) => c.getName() === s).map((c) => c.render(...args))
735
+ );
736
+ });
737
+ return result;
738
+ }
739
+
740
+ /**
741
+ * Vue组件setup方法钩子
742
+ * @param _ctx
743
+ * @param _props
744
+ * @param _result
745
+ * @protected
746
+ */
747
+ protected setupHook(_ctx: void, _props: unknown, _result: unknown): unknown {
748
+ this.behaviorGroup[BehaviorName.beforeCreated]?.();
749
+ this.$$beforeCreated();
750
+ this.beforeCreated();
751
+ this.behaviorGroup[BehaviorName.created]?.();
752
+ this.$$created();
753
+ this.created();
754
+ return {};
755
+ }
756
+
757
+ /**
758
+ * 绑定一个标准的Vue组件或者一个html标签用于当前组件的渲染
759
+ * @param component
760
+ */
761
+ public setComponent(component: WidgetComponent) {
762
+ this.component = {
763
+ inheritAttrs: false,
764
+ ...(component as Component)
765
+ };
766
+ }
767
+
768
+ /**
769
+ * 销毁当前组件
770
+ */
771
+ public dispose(force = false) {
772
+ super.dispose(force);
773
+ this.opt = undefined;
774
+
775
+ const empty = null as any;
776
+
777
+ if (this.__scope) {
778
+ this.__scope.stop();
779
+ this.__scope = empty;
780
+ }
781
+ this.component = empty;
782
+ this.mixinComponent = empty;
783
+ this.widgetComponent = empty;
784
+
785
+ /**
786
+ * 销毁 响应式依赖收集、原型链的属性、事件
787
+ */
788
+ if (force) {
789
+ nextTick(() => {
790
+ this.res = {};
791
+ (this as any).__proto__ = null;
792
+ });
793
+ }
794
+ }
795
+
796
+ /**
797
+ * 获取当前组件渲染时使用的Vue组件
798
+ * @public
799
+ */
800
+ public getComponent() {
801
+ const { name, __render__, __name__ } = this.constructor as Function & { __render__: Function; __name__: string };
802
+ if (!!__render__) {
803
+ this.component = defineComponent({
804
+ name: __name__ || name,
805
+ props: this.buildPropsStrs(),
806
+ render: __render__,
807
+ components: this.getUsingComponents()
808
+ });
809
+ }
810
+ return this.component;
811
+ }
812
+
813
+ /**
814
+ * 获取当前组件引用的其他Vue组件
815
+ * @protected
816
+ */
817
+ protected getUsingComponents(): Record<string, Component> {
818
+ return {};
819
+ }
820
+
821
+ private executeAfterHooks(name: string, result: unknown) {
822
+ const hooks = VueWidget.getHooks(this.getHandle(), name, 'after');
823
+ let index = 0;
824
+ const res = { result };
825
+ const next = () => {
826
+ index < hooks.length && hooks[index++].apply(this, [next, res]);
827
+ };
828
+ next();
829
+ return res.result;
830
+ }
831
+
832
+ private executeBeforeHooks(name: string, ...args: unknown[]) {
833
+ const hooks = VueWidget.getHooks(this.getHandle(), name, 'before');
834
+ let index = 0;
835
+ const _args = { args };
836
+ const next = () => {
837
+ index < hooks.length && hooks[index++].apply(this, [next, _args]);
838
+ };
839
+ next();
840
+ return _args.args;
841
+ }
842
+
843
+ /**
844
+ * Vue钩子
845
+ * @protected
846
+ */
847
+ protected beforeCreated() {}
848
+
849
+ /**
850
+ * @internal
851
+ */
852
+ protected $$beforeCreated() {}
853
+
854
+ /**
855
+ * Vue钩子
856
+ * @protected
857
+ */
858
+ protected created() {}
859
+
860
+ /**
861
+ * @internal
862
+ */
863
+ protected $$created() {}
864
+
865
+ /**
866
+ * Vue钩子
867
+ * @protected
868
+ */
869
+ protected beforeMount() {}
870
+
871
+ /**
872
+ * @internal
873
+ */
874
+ protected $$beforeMount() {}
875
+
876
+ /**
877
+ * Vue钩子
878
+ * @protected
879
+ */
880
+ protected mounted() {}
881
+
882
+ /**
883
+ * @internal
884
+ */
885
+ protected $$mounted() {}
886
+
887
+ /**
888
+ * Vue钩子
889
+ * @protected
890
+ */
891
+ protected beforeUpdate() {}
892
+
893
+ /**
894
+ * @internal
895
+ */
896
+ protected $$beforeUpdate() {}
897
+
898
+ /**
899
+ * Vue钩子
900
+ * @protected
901
+ */
902
+ protected updated() {}
903
+
904
+ /**
905
+ * @internal
906
+ */
907
+ protected $$updated() {}
908
+
909
+ /**
910
+ * Vue钩子
911
+ * @protected
912
+ */
913
+ protected activated() {}
914
+
915
+ /**
916
+ * @internal
917
+ */
918
+ protected $$activated() {}
919
+
920
+ /**
921
+ * Vue钩子
922
+ * @protected
923
+ */
924
+ protected deactivated() {}
925
+
926
+ /**
927
+ * @internal
928
+ */
929
+ protected $$deactivated() {}
930
+
931
+ /**
932
+ * Vue钩子
933
+ * @protected
934
+ */
935
+ protected beforeUnmount() {}
936
+
937
+ /**
938
+ * @internal
939
+ */
940
+ protected $$beforeUnmount() {}
941
+
942
+ /**
943
+ * Vue钩子
944
+ * @protected
945
+ */
946
+ protected unmounted() {}
947
+
948
+ /**
949
+ * @internal
950
+ */
951
+ protected $$unmounted() {}
952
+
953
+ protected $$unmountedAfterProperties() {
954
+ this.dispose();
955
+ }
956
+
957
+ public registryBehavior(name: keyof typeof BehaviorName, cb: () => void) {
958
+ this.behaviorGroup[name] = cb;
959
+ }
960
+
961
+ protected reset() {
962
+ this.widgetComponent = undefined;
963
+ (this.getParent() as VueWidget).node_code = this.revolveNodeCode();
964
+ }
965
+
966
+ @Widget.Reactive()
967
+ protected translate(key, values: { [key: string]: any } = {}): string {
968
+ const translate = Reflect.get(window, 'translate');
969
+
970
+ const result = translate ? translate(key) : '';
971
+
972
+ if (result === key || Object.keys(values).length === 0) {
973
+ return result;
974
+ }
975
+
976
+ const regExp = /\{\s*([A-Z0-9_]+)\s*\}/gi;
977
+
978
+ return result.replace(regExp, (matched: string, k: string): string => values[k]);
979
+ }
980
+
981
+ @Widget.Reactive()
982
+ protected translateByI18n(key: string): string {
983
+ return translateValueByKey(key) || key;
984
+ }
985
+
986
+ @Widget.Method()
987
+ protected genStaticPath(resourceName: string) {
988
+ return genStaticPath(resourceName);
989
+ }
990
+
991
+ public forceUpdate() {
992
+ const opt = this.getOperator();
993
+ if (opt) {
994
+ opt.node_code = this.revolveNodeCode();
995
+ }
996
+ }
997
+ }