compelem 0.20.0-b2 → 0.20.1

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.
package/compelem.umd.js DELETED
@@ -1,4245 +0,0 @@
1
- /**
2
- * compelem v0.20.0-b2.1772633551
3
- * A modern, reactive, fast, lightweight and flexible lib for building web components
4
- * @holyhigh2
5
- * git+https://github.com/holyhigh2/compelem.git
6
- */
7
- (function (global, factory) {
8
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('myfx')) :
9
- typeof define === 'function' && define.amd ? define(['exports', 'myfx'], factory) :
10
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.compelem = {}, global.myfx));
11
- })(this, (function (exports, myfx) { 'use strict';
12
-
13
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
14
-
15
- var myfx__default = /*#__PURE__*/_interopDefaultLegacy(myfx);
16
-
17
- /**
18
- * 样式模板
19
- * @author holyhigh2
20
- */
21
- class CssTemplate {
22
- strings;
23
- vars;
24
- constructor(strings, vars) {
25
- this.strings = myfx.concat(strings);
26
- this.vars = vars;
27
- }
28
- getCss(comp) {
29
- let str = '';
30
- this.strings.forEach((s, i) => {
31
- str = str + s + (this.vars[i] ?? '');
32
- });
33
- return str;
34
- }
35
- destroy() {
36
- this.strings = this.vars = null;
37
- }
38
- }
39
-
40
- const SLOT_NAME_DEFAULT = 'default';
41
- /**
42
- * 共享内容
43
- */
44
- const EXP_KEY = /\s+\.?key\s*=/;
45
- var CollectorType;
46
- (function (CollectorType) {
47
- CollectorType[CollectorType["RENDER"] = 1] = "RENDER";
48
- CollectorType[CollectorType["COMPUTED"] = 2] = "COMPUTED";
49
- CollectorType[CollectorType["DIRECTIVE"] = 3] = "DIRECTIVE";
50
- })(CollectorType || (CollectorType = {}));
51
- var Mode;
52
- (function (Mode) {
53
- Mode["Prod"] = "prod";
54
- Mode["Dev"] = "dev";
55
- })(Mode || (Mode = {}));
56
- const DefinitionCompEventMap = new Map();
57
- const DefinitionTagMap = {};
58
- const DefinitionWatchMap = new Map();
59
- const DefinitionComputedMap = new Map();
60
- const DefinitionStateMap = new Map();
61
- const DefinitionPropMap = new Map();
62
- const DefinitionDecoratorMap = new Map();
63
- const ObservedAttrsMap = new Map();
64
- const ComponentDynamicCssUpdaterMap = new WeakMap();
65
- const PATH_SEPARATOR = '-';
66
-
67
- function showError(msg) {
68
- console.error(`[CompElem]`, msg);
69
- }
70
- function showTagError(tagName, msg) {
71
- console.error(`[CompElem <${tagName}>]`, msg);
72
- }
73
- function showWarn(...args) {
74
- console.warn(`[CompElem]`, ...args);
75
- }
76
- function showTagWarn(tagName, msg) {
77
- console.warn(`[CompElem <${tagName}>]`, msg);
78
- }
79
- //为依赖收集提供标准地址
80
- function _toUpdatePath(varPath) {
81
- return myfx.toPath(varPath).join("-");
82
- }
83
- //获取父类构造
84
- function _getSuper(cls) {
85
- return Object.getPrototypeOf(cls);
86
- }
87
- function isBooleanProp(type) {
88
- return type === Boolean || myfx.some(type, t => t === Boolean);
89
- }
90
- //返回boolean值或非boolean值
91
- function getBooleanValue(v) {
92
- let val = v;
93
- if (myfx.isString(v) && /(?:^true$)|(?:^false$)/.test(val)) {
94
- val = val === 'true' ? true : false;
95
- }
96
- else if (myfx.isUndefined(val) || myfx.isBlank(val)) {
97
- val = true;
98
- }
99
- return val;
100
- }
101
- const DomUtil = {
102
- getNodes(startNode, endNode) {
103
- let nextNode = startNode.nextSibling;
104
- if (!endNode)
105
- return [nextNode];
106
- let rs = [];
107
- while (nextNode && nextNode !== endNode) {
108
- rs.push(nextNode);
109
- nextNode = nextNode?.nextSibling;
110
- }
111
- return rs;
112
- },
113
- insertBefore: function (node, newNodes) {
114
- if (!node.parentNode)
115
- return;
116
- let fragment = document.createDocumentFragment();
117
- fragment.append(...newNodes);
118
- node.parentNode.insertBefore(fragment, node);
119
- },
120
- remove: function (startNode, endNode) {
121
- if (startNode === endNode) {
122
- startNode?.parentNode?.removeChild(startNode);
123
- return;
124
- }
125
- let nextNode = startNode.nextSibling;
126
- while (nextNode && nextNode !== endNode) {
127
- nextNode?.parentNode?.removeChild(nextNode);
128
- nextNode = startNode.nextSibling;
129
- }
130
- },
131
- //清除dom内容并释放内存
132
- clear(container, comp) {
133
- if (!container)
134
- return;
135
- let nodeIterator = document.createNodeIterator(container, NodeFilter.SHOW_COMMENT);
136
- //subscopes
137
- let currentNode;
138
- nodeIterator = document.createNodeIterator(container, NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_ELEMENT);
139
- while ((currentNode = nodeIterator.nextNode())) {
140
- if (container === currentNode)
141
- continue;
142
- if (currentNode instanceof Comment) ;
143
- else if (currentNode instanceof CompElem) {
144
- currentNode.destroy();
145
- }
146
- else ;
147
- }
148
- }
149
- };
150
- function getSlotComponent(node, renderComponent) {
151
- let documentFragment = myfx.closest(node, (n) => n.host && n.host instanceof CompElem, 'parentNode');
152
- if (documentFragment && documentFragment.host === renderComponent)
153
- return undefined;
154
- return documentFragment ? documentFragment.host : undefined;
155
- }
156
-
157
- function prop(options) {
158
- if (arguments.length === 1) {
159
- return (target, propertyKey, descriptor) => {
160
- options.required = options.required || false;
161
- options.attribute = options.attribute === false ? false : true;
162
- defineProp(target, propertyKey, options, descriptor);
163
- };
164
- }
165
- let target = arguments[0], propertyKey = arguments[1], descriptor = arguments[2];
166
- options = { type: undefined, required: false, attribute: true };
167
- if (descriptor && typeof descriptor.type === 'function') {
168
- options = myfx.defaults(descriptor, options);
169
- descriptor = undefined;
170
- }
171
- defineProp(target, propertyKey, options, descriptor);
172
- }
173
- function defineProp(target, propertyKey, options, descriptor) {
174
- if (!myfx.isLowerCaseChar(propertyKey[0])) {
175
- showError(`Prop '${propertyKey}' must be in CamelCase`);
176
- }
177
- let attrSet;
178
- if (!DefinitionPropMap.has(target.constructor.name)) {
179
- const mixinProps = {};
180
- let parentCtor = target.constructor;
181
- while ((parentCtor = _getSuper(parentCtor)) !== CompElem) {
182
- myfx.merge(mixinProps, DefinitionPropMap.get(parentCtor.name) ?? {});
183
- }
184
- attrSet = new Set();
185
- myfx.each(mixinProps, (v, k) => {
186
- if (v.attribute) {
187
- let kbb = myfx.kebabCase(k);
188
- attrSet?.add(kbb);
189
- }
190
- });
191
- ObservedAttrsMap.set(target.constructor.name, attrSet);
192
- DefinitionPropMap.set(target.constructor.name, mixinProps);
193
- }
194
- if (descriptor) {
195
- if (descriptor.get)
196
- options.getter = descriptor.get;
197
- if (descriptor.set)
198
- options.setter = descriptor.set;
199
- }
200
- if (options.attribute) {
201
- if (!attrSet) {
202
- attrSet = ObservedAttrsMap.get(target.constructor.name);
203
- }
204
- let kbb = myfx.kebabCase(propertyKey);
205
- attrSet?.add(kbb);
206
- }
207
- //observeAttrs
208
- if (!myfx.has(target.constructor, 'observedAttributes')) {
209
- target.constructor.observedAttributes = [];
210
- }
211
- if (attrSet)
212
- target.constructor.observedAttributes = myfx.toArray(attrSet);
213
- myfx.set(DefinitionPropMap.get(target.constructor.name), propertyKey, options);
214
- }
215
- //内部接口
216
- const emptySet = new Set;
217
- function _getObservedAttrs(ctor) {
218
- return ObservedAttrsMap.get(ctor.name) ?? emptySet;
219
- }
220
-
221
- /*************************************************************
222
- * 扩展事件
223
- * @author holyhigh2
224
- *
225
- * resize
226
- * outside[.mousedown/mouseup/click/dblclick] 默认click
227
- * mutate[.attr/child/char/tree]
228
- *
229
- *************************************************************/
230
- const ExtEvNames = ['resize', 'outside', 'mutate'];
231
- ///////////////////////////////////////////////// resize
232
- const AllResizeEls = new WeakMap;
233
- const AllOutsideDownEls = [];
234
- const AllOutsideClickEls = [];
235
- const AllOutsideDblClickEls = [];
236
- const resizeObserver = new ResizeObserver((entries) => {
237
- for (const entry of entries) {
238
- const contentBoxSize = Array.isArray(entry.contentBoxSize)
239
- ? entry.contentBoxSize[0]
240
- : entry.contentBoxSize;
241
- const borderBoxSize = Array.isArray(entry.borderBoxSize)
242
- ? entry.borderBoxSize[0]
243
- : entry.borderBoxSize;
244
- let cbk = AllResizeEls.get(entry.target);
245
- if (cbk) {
246
- let ev = new CustomEvent('resize', {
247
- bubbles: false,
248
- cancelable: false,
249
- detail: {
250
- borderBox: { w: borderBoxSize.inlineSize, h: borderBoxSize.blockSize },
251
- contentBox: { w: contentBoxSize.inlineSize, h: contentBoxSize.blockSize },
252
- },
253
- });
254
- cbk(ev, entry.target);
255
- }
256
- }
257
- });
258
- function addResize(node, cbk, component) {
259
- if (AllResizeEls.has(node))
260
- return;
261
- AllResizeEls.set(node, cbk);
262
- resizeObserver.observe(node);
263
- //record
264
- let observer = resizeObserver;
265
- return (remove = false) => {
266
- observer.unobserve(node);
267
- AllResizeEls.delete(node);
268
- if (remove) {
269
- observer = node = null;
270
- }
271
- };
272
- }
273
- ///////////////////////////////////////////////// mutate
274
- var MutationType;
275
- (function (MutationType) {
276
- MutationType["Child"] = "child";
277
- MutationType["Tree"] = "tree";
278
- MutationType["Attr"] = "attr";
279
- MutationType["Char"] = "char";
280
- })(MutationType || (MutationType = {}));
281
- const AllMutationEls = new WeakMap;
282
- const mutationObserver = new MutationObserver(mutations => {
283
- for (let i = 0; i < mutations.length; i++) {
284
- const mutation = mutations[i];
285
- let map = AllMutationEls.get(mutation.target);
286
- if (!map)
287
- return;
288
- let detail = {
289
- target: mutation.target
290
- };
291
- let cbk = null;
292
- switch (mutation.type) {
293
- case 'subtree':
294
- detail.type = MutationType.Tree;
295
- cbk = map[MutationType.Tree];
296
- break;
297
- case "childList":
298
- detail.type = MutationType.Child;
299
- detail.addedNodes = mutation.addedNodes;
300
- detail.removedNodes = mutation.removedNodes;
301
- cbk = map[MutationType.Child];
302
- break;
303
- case "attributes":
304
- detail.type = MutationType.Attr;
305
- detail.attributeName = mutation.attributeName;
306
- detail.oldValue = mutation.oldValue;
307
- cbk = map[MutationType.Attr];
308
- break;
309
- case "characterData":
310
- detail.type = MutationType.Char;
311
- detail.oldValue = mutation.oldValue;
312
- cbk = map[MutationType.Char];
313
- break;
314
- }
315
- if (cbk) {
316
- let ev = new CustomEvent('mutate', {
317
- bubbles: false,
318
- cancelable: false,
319
- detail
320
- });
321
- cbk(ev);
322
- }
323
- }
324
- });
325
- function addMutation(node, cbk, parts, component) {
326
- let child = myfx.includes(parts, 'child');
327
- let attr = myfx.includes(parts, 'attr');
328
- let char = myfx.includes(parts, 'char');
329
- let tree = myfx.includes(parts, 'tree');
330
- let map = AllMutationEls.get(node);
331
- if (map)
332
- return;
333
- map = {};
334
- AllMutationEls.set(node, map);
335
- if (child) {
336
- map[MutationType.Child] = cbk;
337
- }
338
- if (attr) {
339
- map[MutationType.Attr] = cbk;
340
- }
341
- if (char) {
342
- map[MutationType.Char] = cbk;
343
- }
344
- if (tree) {
345
- map[MutationType.Tree] = cbk;
346
- }
347
- mutationObserver.observe(node, {
348
- childList: child,
349
- attributes: attr,
350
- characterData: char,
351
- subtree: tree
352
- });
353
- //record
354
- return (remove = false) => {
355
- AllMutationEls.delete(node);
356
- if (remove) {
357
- node = null;
358
- }
359
- };
360
- }
361
- ///////////////////////////////////////////////// outside
362
- document.addEventListener('mousedown', e => {
363
- let t = myfx.get(e.composedPath(), 0, e.target);
364
- AllOutsideDownEls.forEach(([node, cbk]) => {
365
- if (!node.contains(t) && !node.contains(myfx.closest(t, (node) => node instanceof ShadowRoot, 'parentNode')?.host)) {
366
- let ev = new CustomEvent('outside', {
367
- bubbles: false,
368
- cancelable: false,
369
- detail: {
370
- currentTarget: node,
371
- event: e
372
- },
373
- });
374
- cbk(ev, node);
375
- }
376
- });
377
- }, false);
378
- document.addEventListener('click', e => {
379
- let t = myfx.get(e.composedPath(), 0, e.target);
380
- AllOutsideClickEls.forEach(([node, cbk]) => {
381
- if (!node.contains(t) && !node.contains(myfx.closest(t, (node) => node instanceof ShadowRoot, 'parentNode')?.host)) {
382
- let ev = new CustomEvent('outside', {
383
- bubbles: false,
384
- cancelable: false,
385
- detail: {
386
- currentTarget: node,
387
- event: e
388
- },
389
- });
390
- cbk(ev, node);
391
- }
392
- });
393
- }, false);
394
- document.addEventListener('dblclick', e => {
395
- let t = myfx.get(e.composedPath(), 0, e.target);
396
- AllOutsideDblClickEls.forEach(([node, cbk]) => {
397
- if (!node.contains(t) && !node.contains(myfx.closest(t, (node) => node instanceof ShadowRoot, 'parentNode')?.host)) {
398
- let ev = new CustomEvent('outside', {
399
- bubbles: false,
400
- cancelable: false,
401
- detail: {
402
- currentTarget: node,
403
- event: e
404
- },
405
- });
406
- cbk(ev, node);
407
- }
408
- });
409
- }, false);
410
- function addOutsideMouseDown(node, cbk, component) {
411
- AllOutsideDownEls.push([node, cbk]);
412
- //record
413
- return (remove = false) => {
414
- myfx__default["default"].remove(AllOutsideDownEls, el => el[0] === node && el[1] === cbk);
415
- };
416
- }
417
- function addOutsideClick(node, cbk, component) {
418
- AllOutsideClickEls.push([node, cbk]);
419
- //record
420
- return (remove = false) => {
421
- myfx__default["default"].remove(AllOutsideClickEls, el => el[0] === node && el[1] === cbk);
422
- };
423
- }
424
- function addOutsideDblClick(node, cbk, component) {
425
- AllOutsideDblClickEls.push([node, cbk]);
426
- //record
427
- return (remove = false) => {
428
- myfx__default["default"].remove(AllOutsideDblClickEls, el => el[0] === node && el[1] === cbk);
429
- };
430
- }
431
- function isExtEvent(evName) {
432
- return ExtEvNames.includes(evName);
433
- }
434
- function addExtEvent(evName, node, cbk, parts, component) {
435
- if (evName === 'resize') {
436
- return addResize(node, cbk);
437
- }
438
- else if (evName === 'outside') {
439
- switch (parts[0]) {
440
- case 'mousedown':
441
- return addOutsideMouseDown(node, cbk);
442
- case 'dblclick':
443
- return addOutsideDblClick(node, cbk);
444
- case 'click':
445
- default:
446
- return addOutsideClick(node, cbk);
447
- }
448
- }
449
- else if (evName === 'mutate') {
450
- return addMutation(node, cbk, parts);
451
- }
452
- }
453
-
454
- const MODI_EV_DEBOUNCE = /,|^(debounce:.+)|(debounce$)/;
455
- const MODI_EV_THROTTLE = /,|^(throttle:.+)|(throttle$)/;
456
- const MODI_EV_SELF = 'self';
457
- const MODI_EV_STOP = 'stop';
458
- const MODI_EV_PREVENT = 'prevent';
459
- const MODI_EV_ONCE = 'once';
460
- const MODI_EV_CAPTURE = 'capture';
461
- const MODI_EV_PASSIVE = 'passive';
462
- const MODI_EV_MOUSE_LEFT = 'left';
463
- const MODI_EV_MOUSE_RIGHT = 'right';
464
- const MODI_EV_MOUSE_MIDDLE = 'middle';
465
- const MODI_EV_KEYBOARD_COMBO_CTRL = 'ctrl';
466
- const MODI_EV_KEYBOARD_COMBO_ALT = 'alt';
467
- const MODI_EV_KEYBOARD_COMBO_SHIFT = 'shift';
468
- const MODI_EV_KEYBOARD_COMBO_META = 'meta';
469
- const MODI_EV_KEYBOARD_KEY_MAP = {
470
- 'esc': 'escape'
471
- };
472
- const MODI_PARAM_DIVIDER = ":";
473
- /*************************************************************
474
- * 事件修饰符
475
- * @author holyhigh2
476
- *
477
- * 全部通用 debounce/once/throttle/capture/passive 可组合
478
- * 原生通用 stop/prevent/self 可组合
479
- * 鼠标 left/right/middle 不可组合
480
- * 键盘 ctrl/alt/shift/meta 可组合 esc/letters... 不可组合,多个key并列式表示可选
481
- *
482
- * 部分修饰符支持参数,使用冒号传参如:throttle:100 / debounce:100
483
- *************************************************************/
484
- const VFN = () => { };
485
- function addEvent(fullName, cbk, node, component) {
486
- let parts = fullName.split('.');
487
- let evName = parts.shift();
488
- let isOnce = parts.includes(MODI_EV_ONCE);
489
- let c = cbk ?? VFN;
490
- let modi;
491
- if (modi = myfx.find(parts, x => MODI_EV_DEBOUNCE.test(x))) {
492
- let params = modi.split(MODI_PARAM_DIVIDER);
493
- c = myfx.debounce(c, parseInt(params[1]) || 100);
494
- }
495
- if (modi = myfx.find(parts, x => MODI_EV_THROTTLE.test(x))) {
496
- let params = modi.split(MODI_PARAM_DIVIDER);
497
- c = myfx.throttle(c, parseInt(params[1]) || 100);
498
- }
499
- if (isOnce) {
500
- c = myfx.once(c);
501
- }
502
- if (isExtEvent(evName)) {
503
- return addExtEvent(evName, node, c, parts);
504
- }
505
- let listener = (e) => {
506
- if (parts.includes(MODI_EV_PREVENT))
507
- e.preventDefault();
508
- if (parts.includes(MODI_EV_STOP))
509
- e.stopPropagation();
510
- if (parts.includes(MODI_EV_SELF) && e.target !== e.currentTarget)
511
- return;
512
- if (e instanceof MouseEvent) {
513
- if (parts.includes(MODI_EV_MOUSE_LEFT) && e.button != 0)
514
- return;
515
- if (parts.includes(MODI_EV_MOUSE_RIGHT) && e.button != 2)
516
- return;
517
- if (parts.includes(MODI_EV_MOUSE_MIDDLE) && e.button != 1)
518
- return;
519
- }
520
- else if (e instanceof KeyboardEvent) {
521
- if (myfx.remove(parts, p => p == MODI_EV_KEYBOARD_COMBO_CTRL)[0] && !e.ctrlKey)
522
- return;
523
- if (myfx.remove(parts, p => p == MODI_EV_KEYBOARD_COMBO_ALT)[0] && !e.altKey)
524
- return;
525
- if (myfx.remove(parts, p => p == MODI_EV_KEYBOARD_COMBO_SHIFT)[0] && !e.shiftKey)
526
- return;
527
- if (myfx.remove(parts, p => p == MODI_EV_KEYBOARD_COMBO_META)[0] && !e.metaKey)
528
- return;
529
- let checkKeys = myfx.map(parts, k => MODI_EV_KEYBOARD_KEY_MAP[k] || k);
530
- if (myfx.size(checkKeys) > 0 && !checkKeys.includes(e.key.toLowerCase()))
531
- return;
532
- }
533
- console.debug(evName, c.name, node.tagName);
534
- c(e);
535
- };
536
- let capture = parts.includes(MODI_EV_CAPTURE) || false;
537
- let passive = parts.includes(MODI_EV_PASSIVE) || false;
538
- let options = { capture, passive };
539
- node.addEventListener(evName, listener, options);
540
- //record
541
- return (remove = false) => {
542
- node.removeEventListener(evName, listener, options);
543
- if (remove)
544
- node = null;
545
- };
546
- }
547
-
548
- /**
549
- * 用于提供全局state状态管理
550
- * @author holyhigh2
551
- */
552
- const Collector = {
553
- popDirectiveQ() {
554
- let rs = this.__varPathList.reduceRight((acc, p) => {
555
- if (!acc.includes(p)) {
556
- acc.unshift(p);
557
- }
558
- return acc;
559
- }, []);
560
- return rs;
561
- },
562
- start() {
563
- this.__collecting = true;
564
- this.__varPathList = [];
565
- },
566
- end(renderComponent, up) {
567
- if (renderComponent && up) {
568
- renderComponent._regSubViewDeps(Collector.popVarPathList(), up);
569
- }
570
- this.__collecting = false;
571
- },
572
- popVarPathList() {
573
- let rs = Array.from(new Set(this.__varPathList));
574
- this.__varPathList = [];
575
- return rs;
576
- },
577
- __varPathList: [],
578
- __collecting: false,
579
- };
580
- //对象值在不同上下文的根路径
581
- const OBJECT_VAR_ROOT_PATH_IN_CONTEXT = new WeakMap();
582
- const OBJECT_VAR_PATH = new WeakMap();
583
- //缓存已经创建的proxy对象
584
- const PROXY_MAP = new WeakMap();
585
- //对象值的创建上下文
586
- const OBJECT_VAR_ROOT_CONTEXT = new WeakMap();
587
- //上级对象所在的扩展context
588
- const EXTRA_CONTEXT_OF_VAR = new WeakMap();
589
- function reactive(obj, context, rootProp) {
590
- if (PROXY_MAP.has(obj))
591
- return PROXY_MAP.get(obj);
592
- if (OBJECT_VAR_ROOT_CONTEXT.has(obj)) {
593
- if (rootProp) {
594
- let pathMap = OBJECT_VAR_ROOT_PATH_IN_CONTEXT.get(context);
595
- if (!pathMap) {
596
- pathMap = new WeakMap();
597
- OBJECT_VAR_ROOT_PATH_IN_CONTEXT.set(context, pathMap);
598
- }
599
- pathMap.set(obj, rootProp);
600
- let contextList = EXTRA_CONTEXT_OF_VAR.get(obj);
601
- if (!contextList) {
602
- contextList = new Set();
603
- EXTRA_CONTEXT_OF_VAR.set(obj, contextList);
604
- }
605
- contextList.add(context);
606
- }
607
- return obj;
608
- }
609
- const proxyObject = new Proxy(obj, {
610
- get(target, prop, receiver) {
611
- if (!prop)
612
- return undefined;
613
- const value = Reflect.get(target, prop, receiver);
614
- if (myfx.isSymbol(prop))
615
- return value;
616
- if (myfx.isFunction(value))
617
- return value;
618
- if (prop === 'length' && myfx.isArray(target))
619
- return value;
620
- if (Collector.__collecting) {
621
- let supPath = OBJECT_VAR_PATH.has(receiver) ? myfx.concat(OBJECT_VAR_PATH.get(receiver)) : [];
622
- supPath.push(prop);
623
- let propPath = supPath.join('.');
624
- Collector.__varPathList.push(propPath);
625
- }
626
- if (PROXY_MAP.has(value))
627
- return PROXY_MAP.get(value);
628
- let reactiveVal = value;
629
- if (myfx.isObject(value) && !myfx.isFunction(value) && !(value instanceof Node) && !Object.isFrozen(value)) {
630
- reactiveVal = reactive(value, context);
631
- let supPath = OBJECT_VAR_PATH.has(receiver) ? myfx.concat(OBJECT_VAR_PATH.get(receiver)) : [];
632
- supPath.push(prop);
633
- OBJECT_VAR_PATH.set(reactiveVal, supPath);
634
- PROXY_MAP.set(value, reactiveVal);
635
- }
636
- return reactiveVal;
637
- },
638
- set(target, prop, newValue, receiver) {
639
- if (!prop)
640
- return false;
641
- let ov = target[prop];
642
- let chain = OBJECT_VAR_PATH.get(receiver) ?? [];
643
- let subChain = myfx.concat(chain, [prop]);
644
- let hasChanged = context._hasChangedPropOrStateMap?.get(subChain[0]);
645
- let moreThan1 = subChain.length > 1;
646
- let rootObjNew = newValue;
647
- let rootObjOld = ov;
648
- if (moreThan1) {
649
- rootObjOld = rootObjNew = context._getPrivateData()[subChain[0]];
650
- }
651
- if (hasChanged) {
652
- if (!hasChanged.call(context, rootObjNew, rootObjOld, subChain, newValue, ov))
653
- return true;
654
- }
655
- else {
656
- //默认对比算法
657
- if (Object.is(ov, newValue)) {
658
- return true;
659
- }
660
- }
661
- let nv = newValue;
662
- let rs = Reflect.set(target, prop, nv);
663
- let extraContext = EXTRA_CONTEXT_OF_VAR.get(receiver);
664
- let k = subChain.join('.');
665
- //check watch
666
- context._requestWatchUpdate(nv, ov, k, rootObjNew, rootObjOld);
667
- //check computed
668
- context._requestComputedUpdate(k);
669
- notifyUpdate(context, rootObjOld, subChain);
670
- myfx.each(extraContext, ctx => {
671
- let ctxRootPath = ctx._wrapperProp[subChain[0]];
672
- let ck = subChain.join('.');
673
- ck = ck.replace(subChain[0], ctxRootPath);
674
- //check watch
675
- ctx._requestWatchUpdate(nv, ov, ck);
676
- //check computed
677
- ctx._requestComputedUpdate(ck);
678
- notifyUpdate(ctx, rootObjOld, ck.split('.'));
679
- });
680
- return rs;
681
- }
682
- });
683
- if (!OBJECT_VAR_PATH.has(proxyObject)) {
684
- OBJECT_VAR_PATH.set(proxyObject, rootProp ? [rootProp] : []);
685
- }
686
- PROXY_MAP.set(obj, proxyObject);
687
- if (rootProp) {
688
- OBJECT_VAR_ROOT_CONTEXT.set(proxyObject, context);
689
- if (!OBJECT_VAR_ROOT_PATH_IN_CONTEXT.has(context)) {
690
- let pathMap = new WeakMap();
691
- pathMap.set(proxyObject, rootProp);
692
- OBJECT_VAR_ROOT_PATH_IN_CONTEXT.set(context, pathMap);
693
- }
694
- }
695
- return proxyObject;
696
- }
697
- function notifyUpdate(context, oldValue, path, subNewValue, subOldValue) {
698
- let i = myfx.size(path);
699
- myfx.eachRight(path, (p) => {
700
- let varPath = myfx.slice(path, 0, i--);
701
- context._notify(oldValue, varPath);
702
- });
703
- }
704
- const QMap = new Map();
705
- class Queue {
706
- static nextSet = new Set();
707
- static nextPending = false;
708
- static next;
709
- static flush() {
710
- Queue.nextPending = false;
711
- let nq = Array.from(Queue.nextSet);
712
- Queue.nextSet.clear();
713
- QMap.clear();
714
- nq.forEach(u => u());
715
- nq = null;
716
- }
717
- static pushNext(updater) {
718
- Queue.nextSet.add(updater);
719
- if (!Queue.nextPending) {
720
- Queue.nextPending = true;
721
- Queue.next();
722
- }
723
- }
724
- }
725
- (() => {
726
- const p = Promise.resolve();
727
- const nextFn = Queue.flush;
728
- Queue.next = () => {
729
- p.then(nextFn);
730
- };
731
- })();
732
-
733
- const PropTypeMap = {
734
- boolean: Boolean,
735
- string: String,
736
- number: Number,
737
- object: Object,
738
- array: Array,
739
- function: Function,
740
- undefined: Object
741
- };
742
- //组件静态样式
743
- const ComponentStaticStyleMap = new WeakMap();
744
- let DefaultCss = [];
745
- let CompElemSn = 0;
746
- const SlotCompMap = new WeakMap();
747
- const EMPTY_SLOTS = {};
748
- const PROP_NAME_SLOTS = 'slots';
749
- /**
750
- * CompElem基类,意为组件元素。提供了基本内置属性及生命周期等必备接口
751
- * 每个组件都需要继承自该类
752
- *
753
- * @author holyhigh2
754
- */
755
- class CompElem extends HTMLElement {
756
- static __l_globalRule = document.createElement("style");
757
- //设置全局/组件默认属性
758
- static defaults(options) {
759
- DefaultCss = myfx.flatMap(options.css, c => {
760
- if (myfx.isString(c)) {
761
- let sheet = new CSSStyleSheet();
762
- sheet.replaceSync(c);
763
- return sheet;
764
- }
765
- else if (c instanceof CSSStyleSheet) {
766
- return c;
767
- }
768
- return [];
769
- });
770
- //todo...
771
- options.global;
772
- myfx.each(options, (v, k) => {
773
- if (myfx.test(k[0], /[A-Z]/)) ;
774
- });
775
- }
776
- #cid;
777
- #slotPropsMap = {};
778
- #data = {};
779
- #updateSources = {};
780
- #shadow;
781
- //保存所有渲染上下文 {CompElem/Directive}
782
- __updateTree;
783
- __cssSheets;
784
- _eventList;
785
- __docoEventMap;
786
- __updateCssDeps;
787
- __updateSubViewDeps;
788
- __updateViewDeps;
789
- _watchUpdateMap;
790
- _watchDeepUpdateMap;
791
- _watchKeys;
792
- _watchKeysOnceMap;
793
- _watchKeysDeep;
794
- _watchUpdateSetInNextTick;
795
- _watchUpdateArgsInNextTick;
796
- _computedUpdateDeps;
797
- _computedUpdateSetInNextTick;
798
- _hasChangedPropOrStateMap;
799
- _hasSyncPropSet;
800
- _hasShallowStateSet;
801
- get [Symbol.toStringTag]() {
802
- return this.constructor.name;
803
- }
804
- get cid() {
805
- return this.#cid;
806
- }
807
- get attrs() {
808
- return this.#attrs;
809
- }
810
- get props() {
811
- return this.#props;
812
- }
813
- get renderRoot() {
814
- return this.#renderRoot?.deref();
815
- }
816
- get renderRoots() {
817
- return this.#renderRoots.flatMap(wr => wr.deref() ?? []);
818
- }
819
- get parentComponent() {
820
- return this.#parentComponent?.deref();
821
- }
822
- get wrapperComponent() {
823
- return this.#wrapperComponent?.deref();
824
- }
825
- get slotHooks() {
826
- return this.#slotHooks;
827
- }
828
- get styleSheets() {
829
- return ComponentStaticStyleMap.get(this);
830
- }
831
- get globalStyleSheet() {
832
- return CompElem.__l_globalRule.sheet;
833
- }
834
- get isMounted() {
835
- return this.#mounted;
836
- }
837
- get slots() {
838
- return EMPTY_SLOTS;
839
- }
840
- #attrs;
841
- #props;
842
- #renderRoot;
843
- #renderRoots;
844
- #parentComponent;
845
- #wrapperComponent;
846
- #slotsEl = {};
847
- #slotHooks = {};
848
- #slotNodes = {};
849
- #mounted = false;
850
- #updateViewImmediately = false;
851
- #updateNextImmediatelyQ;
852
- //////////////////////////////////// styles
853
- /**
854
- * 组件样式,CSSStyleSheet可动态变更
855
- */
856
- static get styles() {
857
- return [];
858
- }
859
- static get globalStyle() {
860
- return undefined;
861
- }
862
- static get hostStyle() {
863
- return undefined;
864
- }
865
- get styles() {
866
- return [];
867
- }
868
- #inited = false;
869
- #initiating = false;
870
- constructor(...args) {
871
- super();
872
- this.#cid = CompElemSn++;
873
- this.__updateTree = [];
874
- //init props via constructor
875
- if (myfx.size(args) === 1) {
876
- this.#props = {};
877
- myfx.assign(this.#props, myfx.first(args));
878
- }
879
- /////////////////////////////////////////////////// slots
880
- // this.#updateSlotsAry()
881
- /////////////////////////////////////////////////// decorators create
882
- let ary = DefinitionDecoratorMap.get(this.constructor.name) ?? DefinitionDecoratorMap.get(_getSuper(this.constructor).name);
883
- ary && ary.sort((a, b) => b.priority - a.priority).forEach(dw => dw.create(this));
884
- this.#updatedD = this.#update.bind(this);
885
- }
886
- insertStyleSheet(sheet) {
887
- if (!this.#shadow)
888
- return null;
889
- let cssSheet;
890
- if (myfx.isString(sheet)) {
891
- cssSheet = new CSSStyleSheet();
892
- try {
893
- cssSheet.replaceSync(sheet);
894
- }
895
- catch (e) {
896
- }
897
- }
898
- else {
899
- if (this.#shadow.adoptedStyleSheets.includes(sheet))
900
- return sheet;
901
- cssSheet = sheet;
902
- }
903
- this.#shadow.adoptedStyleSheets = [...this.#shadow.adoptedStyleSheets, cssSheet];
904
- // Keep ComponentStyleMap in sync for this constructor
905
- const cur = ComponentStaticStyleMap.get(this) ?? [];
906
- cur.push(cssSheet);
907
- return cssSheet;
908
- }
909
- /**
910
- * Returns the root component in the parent chain, or itself if it's the top-level component.
911
- */
912
- get rootComponent() {
913
- let comp = this;
914
- while (comp.parentComponent) {
915
- comp = comp.parentComponent;
916
- }
917
- return comp;
918
- }
919
- #updatedD;
920
- connectedCallback() {
921
- //parent
922
- let node = myfx.closest(this.parentNode, (node) => node instanceof CompElem || node.host instanceof CompElem, "parentNode");
923
- this.#parentComponent = node
924
- ? node instanceof CompElem
925
- ? new WeakRef(node)
926
- : new WeakRef(node.host)
927
- : undefined;
928
- if (!CompElem.__l_globalRule.parentNode) {
929
- document.head.appendChild(CompElem.__l_globalRule);
930
- }
931
- //host styles
932
- let hostStyle = myfx.get(this.constructor, "hostStyle");
933
- let styleSheet = myfx.get(this.constructor, 'hostStyleSheet');
934
- if (hostStyle) {
935
- if (!styleSheet) {
936
- if (myfx.isString(hostStyle)) {
937
- styleSheet = new CSSStyleSheet();
938
- styleSheet.replaceSync(hostStyle);
939
- }
940
- else {
941
- styleSheet = hostStyle;
942
- }
943
- myfx.set(this.constructor, 'hostStyleSheet', styleSheet);
944
- }
945
- let styleRoot = this.#wrapperComponent?.deref()?.shadowRoot ?? this.#parentComponent?.deref()?.shadowRoot ?? this.ownerDocument;
946
- //detached el
947
- if (this.#wrapperComponent && !this.#wrapperComponent.deref()?.shadowRoot?.contains(this)) {
948
- styleRoot = myfx.closest(this, n => n instanceof HTMLDocument || n instanceof ShadowRoot, 'parentNode');
949
- }
950
- if (styleRoot && styleSheet && !styleRoot.adoptedStyleSheets.includes(styleSheet)) {
951
- styleRoot.adoptedStyleSheets = [...styleRoot.adoptedStyleSheets, styleSheet];
952
- }
953
- }
954
- this.__init();
955
- this.__bindEvents();
956
- }
957
- disconnectedCallback() {
958
- this.__unbindEvents();
959
- }
960
- __bindEvents() {
961
- let evs = this._eventList;
962
- myfx.each(evs, (v) => {
963
- let [evName, cbk, node, binded] = v;
964
- if (binded)
965
- return;
966
- if (!node)
967
- return;
968
- let handler = cbk ? cbk.bind(this) : cbk;
969
- let unbinder = addEvent(evName, handler, node);
970
- v[3] = unbinder;
971
- });
972
- //event decoration
973
- let events = DefinitionCompEventMap.get(this.constructor.name);
974
- if (myfx.size(events) > 0) {
975
- if (!this.__docoEventMap)
976
- this.__docoEventMap = new Map();
977
- myfx.each(events, ({ name, targetFn, fnName }) => {
978
- if (this.__docoEventMap.has(name + "@" + fnName))
979
- return;
980
- let eventTarget = targetFn ? targetFn(this) : this;
981
- let cbk = myfx.get(this, fnName);
982
- let handler = cbk ? cbk.bind(this) : cbk;
983
- let unbinder = addEvent(name, handler, eventTarget);
984
- this.__docoEventMap.set(name + "@" + fnName, unbinder);
985
- });
986
- }
987
- }
988
- __unbindEvents() {
989
- myfx.each(this._eventList, (v) => {
990
- let [, , , unbinder] = v;
991
- if (unbinder)
992
- unbinder();
993
- v[3] = null;
994
- });
995
- let delDecoKeys = [];
996
- myfx.each(this.__docoEventMap, (unbinder, k) => {
997
- if (unbinder)
998
- unbinder();
999
- delDecoKeys.push(k);
1000
- });
1001
- delDecoKeys.forEach(k => this.__docoEventMap.delete(k));
1002
- }
1003
- beforeDestroyed() {
1004
- }
1005
- destroyed() {
1006
- }
1007
- get isDestroyed() {
1008
- return this.#destroyed;
1009
- }
1010
- #destroyed = false;
1011
- destroy() {
1012
- if (this.#destroyed)
1013
- return;
1014
- this.#destroyed = true;
1015
- let ary = DefinitionDecoratorMap.get(this.constructor.name) ?? DefinitionDecoratorMap.get(_getSuper(this.constructor).name);
1016
- ary && ary.sort((a, b) => b.priority - a.priority).forEach(dw => {
1017
- dw.destroy(this);
1018
- });
1019
- this.beforeDestroyed();
1020
- //events
1021
- this.__unbindEvents();
1022
- myfx.each(this.#rootEvs, (hooks, evName) => {
1023
- myfx.each(hooks, hook => {
1024
- this.removeEventListener(evName, hook);
1025
- });
1026
- this.#rootEvs[evName] = null;
1027
- });
1028
- myfx.each(this.#nodeEvs, (hooks, evName) => {
1029
- myfx.each(hooks, ([hook, ref]) => {
1030
- ref.deref()?.removeEventListener(evName, hook);
1031
- });
1032
- this.#nodeEvs[evName] = null;
1033
- });
1034
- this.__docoEventMap?.clear();
1035
- this.__docoEventMap = this._eventList = null;
1036
- //styles
1037
- ComponentStaticStyleMap.delete(this);
1038
- ComponentDynamicCssUpdaterMap.get(this)?.clear();
1039
- ComponentDynamicCssUpdaterMap.delete(this);
1040
- //reactive
1041
- this._watchUpdateArgsInNextTick?.clear();
1042
- this._watchUpdateSetInNextTick?.clear();
1043
- this._watchKeysOnceMap?.clear();
1044
- this._watchUpdateMap = this._watchDeepUpdateMap = this._watchKeys = this._watchKeysDeep = this._watchKeysOnceMap = null;
1045
- this._computedUpdateDeps?.clear();
1046
- this._computedUpdateSetInNextTick?.clear();
1047
- this._computedUpdateDeps = this._computedUpdateSetInNextTick = null;
1048
- this.__updateCssDeps = this.__updateViewDeps = null;
1049
- this.__updateSubViewDeps?.clear();
1050
- this._hasChangedPropOrStateMap?.clear();
1051
- this._hasShallowStateSet?.clear();
1052
- this._hasSyncPropSet?.clear();
1053
- this._hasChangedPropOrStateMap = this._hasShallowStateSet = this._hasSyncPropSet = null;
1054
- //sup scope
1055
- if (this.#parentComponent) {
1056
- let pComp = this.#parentComponent.deref();
1057
- pComp && myfx.walkTree(pComp.__updateTree, (up) => {
1058
- if (up.__destroyed)
1059
- return;
1060
- if (up.node?.deref() === this) {
1061
- up.destroy(pComp);
1062
- myfx.remove(up.parent ? up.parent.children : pComp.__updateTree, c => c === up);
1063
- }
1064
- });
1065
- }
1066
- //sub scopes
1067
- myfx.each(this.__updateTree, up => up?.destroy(this));
1068
- //slots
1069
- myfx.each(this.#slotsEl, (slotEl) => {
1070
- SlotCompMap.delete(slotEl);
1071
- slotEl.remove();
1072
- });
1073
- myfx.each(this.#slotNodes, (nodes) => {
1074
- myfx.each(nodes, (node) => node.remove());
1075
- });
1076
- myfx.each(this.#data.slots, (nodes, k) => {
1077
- myfx.each(nodes, (node) => node.remove());
1078
- });
1079
- this.#updateSlots.clear();
1080
- this.#updateSlots = this.#slotPropsMap = this.#data.slots = null;
1081
- this.remove();
1082
- //data
1083
- this._wrapperProp =
1084
- this.#slotNodes =
1085
- this.#propsReady =
1086
- this.#renderRoot = this.#renderRoots = this.#shadow =
1087
- this.#rootEvs =
1088
- this.#nodeEvs =
1089
- this.#updateSources =
1090
- this.#attrs =
1091
- this.#props =
1092
- this.#renderRoot =
1093
- this.#renderRoots =
1094
- this.#slotHooks =
1095
- this.#updatedD =
1096
- this.#data =
1097
- this.#slotsEl =
1098
- this.__updateTree =
1099
- this.#parentComponent =
1100
- this._asyncDirectives =
1101
- this.#wrapperComponent = null;
1102
- //unmount
1103
- this.destroyed();
1104
- }
1105
- //////////////////////////////////// lifecycles
1106
- //********************************** 首次渲染
1107
- //构造时上级传递的参数
1108
- __init() {
1109
- if (this.#inited)
1110
- return;
1111
- //防止在钩子中出现重新挂载的情况
1112
- if (this.#initiating)
1113
- return;
1114
- this.#initiating = true;
1115
- let thisRef = new WeakRef(this);
1116
- //global styles
1117
- let globalTextContent = myfx.get(this.constructor, "globalStyle");
1118
- if (!myfx.isEmpty(globalTextContent) && myfx.isString(globalTextContent) && !myfx.get(this.constructor, '_globalRuleInserted')) {
1119
- CompElem.__l_globalRule.textContent += globalTextContent; //.sheet?.insertRule(globalTextContent, 0)
1120
- myfx.set(this.constructor, '_globalRuleInserted', true);
1121
- }
1122
- //component styles
1123
- let beAttached2 = ComponentStaticStyleMap.get(this);
1124
- let styleSheets = beAttached2 ?? [];
1125
- if (!beAttached2) {
1126
- myfx.each(myfx.get(this.constructor, "styles"), (st) => {
1127
- if (myfx.isString(st)) {
1128
- let sheet = new CSSStyleSheet();
1129
- sheet.replaceSync(st);
1130
- styleSheets.push(sheet);
1131
- }
1132
- else if (myfx.isFunction(st)) ;
1133
- else {
1134
- styleSheets.push(st);
1135
- }
1136
- });
1137
- ComponentStaticStyleMap.set(this, styleSheets);
1138
- }
1139
- ////////////////////////////////////////////////// Props & States
1140
- const props = this.#initProps();
1141
- this.propsReady(props);
1142
- for (const key in props) {
1143
- const v = props[key];
1144
- this.#data[key] = v;
1145
- }
1146
- this.#initStates();
1147
- //2. Data
1148
- this.#data.slots = {};
1149
- myfx.each(this.#data, (v, k) => {
1150
- let descr = Reflect.getOwnPropertyDescriptor(this.#data, k);
1151
- Reflect.defineProperty(this, k, {
1152
- get() {
1153
- let thisHost = thisRef.deref();
1154
- let v = descr?.get ? descr?.get() : Reflect.get(thisHost.#data, k);
1155
- if (Collector.__collecting) {
1156
- Collector.__varPathList.push(k);
1157
- }
1158
- if (PROXY_MAP.has(v)) {
1159
- let contextList = EXTRA_CONTEXT_OF_VAR.get(v);
1160
- if (!contextList) {
1161
- contextList = new Set();
1162
- EXTRA_CONTEXT_OF_VAR.set(v, contextList);
1163
- }
1164
- contextList.add(thisHost);
1165
- return PROXY_MAP.get(v);
1166
- }
1167
- if (myfx.isObject(v) && !myfx.isFunction(v) && !(v instanceof Node) && !Object.isFrozen(v)) {
1168
- let shallow = thisHost._hasShallowStateSet?.has(k);
1169
- v = shallow || k === PROP_NAME_SLOTS ? v : reactive(v, this, k);
1170
- }
1171
- return v;
1172
- },
1173
- set(v) {
1174
- if (descr?.set) {
1175
- descr?.set(v);
1176
- }
1177
- else {
1178
- let thisHost = thisRef.deref();
1179
- if (!thisHost.#inited) {
1180
- Reflect.set(thisHost.#data, k, v);
1181
- return;
1182
- }
1183
- let oldValue = thisHost.#data[k];
1184
- let hasChanged = thisHost._hasChangedPropOrStateMap?.get(k);
1185
- if (hasChanged) {
1186
- if (!hasChanged.call(thisHost, v, oldValue, [k], v, oldValue))
1187
- return true;
1188
- }
1189
- else {
1190
- //默认对比算法
1191
- if (Object.is(oldValue, v)) {
1192
- return true;
1193
- }
1194
- }
1195
- //check watch
1196
- thisHost._requestWatchUpdate(v, oldValue, k);
1197
- //check computed
1198
- thisHost._requestComputedUpdate(k);
1199
- Reflect.set(thisHost.#data, k, v);
1200
- thisHost._notify(oldValue, [k]);
1201
- //update sync
1202
- if (thisHost._hasSyncPropSet?.has(k)) {
1203
- thisHost.emit('update' + ":" + k, { value: v });
1204
- }
1205
- }
1206
- },
1207
- });
1208
- });
1209
- Reflect.defineProperty(this.#data, '__isData', {
1210
- enumerable: false,
1211
- value: true
1212
- });
1213
- //3. Watch
1214
- let watchMap = DefinitionWatchMap.get(this.constructor.name) ?? DefinitionWatchMap.get(_getSuper(this.constructor).name);
1215
- if (watchMap) {
1216
- this._watchUpdateMap = {};
1217
- this._watchDeepUpdateMap = {};
1218
- this._watchKeys = [];
1219
- this._watchKeysDeep = [];
1220
- this._watchUpdateSetInNextTick = new Set();
1221
- this._watchUpdateArgsInNextTick = new Map();
1222
- this._watchKeysOnceMap = new Map();
1223
- myfx.each(watchMap, (watchList, k) => {
1224
- watchList.forEach(v => {
1225
- let { source, options, handler } = v;
1226
- let fn = handler;
1227
- let onceWatch = myfx.get(options, "once", false);
1228
- if (onceWatch) {
1229
- this._watchKeysOnceMap.set(k, false);
1230
- }
1231
- let deep = myfx.get(options, "deep", false);
1232
- this._watchKeys.push(k);
1233
- if (deep) {
1234
- this._watchDeepUpdateMap[k] = this._watchDeepUpdateMap[k] ?? new Set();
1235
- this._watchDeepUpdateMap[k].add(fn);
1236
- this._watchKeysDeep.push(k);
1237
- }
1238
- else {
1239
- this._watchUpdateMap[k] = this._watchUpdateMap[k] ?? new Set();
1240
- this._watchUpdateMap[k].add(fn);
1241
- }
1242
- let immediate = myfx.get(options, "immediate", false);
1243
- if (!immediate)
1244
- return;
1245
- let nv = myfx.get(this, source);
1246
- fn.call(this, nv, undefined, source);
1247
- if (onceWatch) {
1248
- this._watchKeysOnceMap.set(k, true);
1249
- }
1250
- });
1251
- });
1252
- }
1253
- //4. Computed
1254
- let computedMap = DefinitionComputedMap.get(this.constructor.name) ?? DefinitionComputedMap.get(_getSuper(this.constructor).name);
1255
- if (computedMap) {
1256
- this._computedUpdateDeps = new Map();
1257
- this._computedUpdateSetInNextTick = new Set();
1258
- myfx.each(computedMap, (getter, propKey) => {
1259
- myfx.set(getter, 'key', propKey);
1260
- Collector.start();
1261
- this.#data[propKey] = getter.call(this);
1262
- Collector.end();
1263
- let computedDeps = Collector.popVarPathList();
1264
- computedDeps.forEach(dep => {
1265
- let list = this._computedUpdateDeps.get(dep);
1266
- if (!list) {
1267
- list = new Set();
1268
- this._computedUpdateDeps.set(dep, list);
1269
- }
1270
- list.add(getter);
1271
- });
1272
- Reflect.defineProperty(this, propKey, {
1273
- get() {
1274
- let v = Reflect.get(thisRef.deref().#data, propKey);
1275
- if (Collector.__collecting) {
1276
- Collector.__varPathList.push(propKey);
1277
- }
1278
- return v;
1279
- }
1280
- });
1281
- });
1282
- }
1283
- //5. Render
1284
- Collector.start();
1285
- let tmpl = this.render();
1286
- Collector.end();
1287
- let nodes;
1288
- if (tmpl === null) {
1289
- this.#renderRoots = [];
1290
- this.#renderRoot = undefined;
1291
- }
1292
- else {
1293
- /////////////////////////////////////////////////// shadow dom
1294
- this.#shadow = this.attachShadow({
1295
- mode: "open"
1296
- });
1297
- let viewDeps = Collector.popVarPathList();
1298
- this.__updateViewDeps = viewDeps;
1299
- this.#shadow.adoptedStyleSheets = [...DefaultCss, ...(ComponentStaticStyleMap.get(this) ?? [])];
1300
- nodes = buildView(tmpl, this);
1301
- if (nodes) {
1302
- this.#renderRoots = myfx.filter(nodes, (n) => n.nodeType === Node.ELEMENT_NODE).map(n => new WeakRef(n));
1303
- this.#renderRoot = new WeakRef(nodes[0]);
1304
- }
1305
- }
1306
- this.#inited = true;
1307
- /////////////////////////////////////////////////// slots
1308
- this.#updateSlotsAry();
1309
- //slot hook
1310
- myfx.each(this.#slotHooks, (v, k) => {
1311
- this.#updateSlot(k);
1312
- });
1313
- const that = this;
1314
- let ary = DefinitionDecoratorMap.get(this.constructor.name) ?? DefinitionDecoratorMap.get(_getSuper(this.constructor).name);
1315
- ary && ary.sort((a, b) => b.priority - a.priority).forEach(dw => {
1316
- dw.beforeMount(this, (key, value) => {
1317
- that.#data[key] = value;
1318
- return that.#data[key];
1319
- });
1320
- });
1321
- this.beforeMount();
1322
- setTimeout(() => {
1323
- if (this.isDestroyed) {
1324
- console.debug('Component is destroyed before mount', this.tagName);
1325
- return;
1326
- }
1327
- this.#mounted = true;
1328
- if (this.#shadow) {
1329
- //instance dynamic style
1330
- let cssAry = [];
1331
- Collector.start();
1332
- let cssTmpls = this.styles;
1333
- Collector.end();
1334
- this.__updateCssDeps = Collector.popVarPathList();
1335
- cssTmpls.forEach(cssTmpl => {
1336
- let cssss = new CSSStyleSheet();
1337
- cssAry.push(cssss);
1338
- let css = cssTmpl.getCss(this);
1339
- if (myfx.isBlank(css))
1340
- return;
1341
- cssss.replaceSync(css);
1342
- });
1343
- if (cssAry.length > 0) {
1344
- this.__cssSheets = cssAry;
1345
- this.#shadow.adoptedStyleSheets = [...this.#shadow.adoptedStyleSheets, ...cssAry];
1346
- }
1347
- }
1348
- if (nodes)
1349
- this.#shadow.append(...nodes);
1350
- ary && ary.forEach(dw => {
1351
- dw.mounted(this, (key, value) => {
1352
- that.#data[key] = value;
1353
- return that.#data[key];
1354
- });
1355
- });
1356
- if (this.#updateNextImmediatelyQ) {
1357
- this.#updateNextImmediatelyQ.forEach((cbk) => Queue.pushNext(cbk));
1358
- }
1359
- if (this.#updateViewImmediately) {
1360
- Queue.pushNext(this.#updatedD);
1361
- }
1362
- this.__bindEvents();
1363
- this.mounted();
1364
- }, 0);
1365
- }
1366
- propsReady(props) { }
1367
- render() {
1368
- return null;
1369
- }
1370
- beforeMount() { }
1371
- mounted() { }
1372
- __onSlotChangeHook(e) {
1373
- let t = e.currentTarget;
1374
- let name = '';
1375
- myfx.each(this.#slotsEl, (el, n) => {
1376
- if (el === t) {
1377
- name = n;
1378
- return false;
1379
- }
1380
- });
1381
- if (this.#inited)
1382
- this.#onSlotChange(t, name === SLOT_NAME_DEFAULT ? '' : name);
1383
- }
1384
- #onSlotChange(slot, name) {
1385
- //1. 更新 _slotsPropMap & slots
1386
- this.#updateSlotsAry();
1387
- //2. 设置attrs
1388
- let props = myfx.get(this.#slotPropsMap[name], 'props');
1389
- if (props) {
1390
- myfx.each(this.slots, (nodeAry, k) => {
1391
- nodeAry.filter(node => node.nodeType === Node.ELEMENT_NODE).forEach((node) => {
1392
- if (node instanceof CompElem) {
1393
- node._updateProps(props);
1394
- return;
1395
- }
1396
- myfx.each(props, (v, k) => {
1397
- if (node instanceof HTMLSlotElement) {
1398
- let compOfSlot = SlotCompMap.get(node);
1399
- if (compOfSlot) {
1400
- let sname = node.name || SLOT_NAME_DEFAULT;
1401
- let slotMap = compOfSlot.#slotPropsMap[sname];
1402
- if (!slotMap) {
1403
- slotMap = compOfSlot.#slotPropsMap[sname] = { props: {} };
1404
- }
1405
- if (!slotMap.props) {
1406
- slotMap.props = {};
1407
- }
1408
- slotMap.props[k] = v;
1409
- compOfSlot.#onSlotChange(node, sname);
1410
- }
1411
- }
1412
- else {
1413
- node.setAttribute(k, v);
1414
- }
1415
- });
1416
- });
1417
- });
1418
- }
1419
- //3. callback
1420
- this.slotChange(slot, name);
1421
- }
1422
- slotChange(slot, name) { }
1423
- attributeChangedCallback(attributeName, oldValue, newValue) {
1424
- if (!this.#inited)
1425
- return;
1426
- if (Object.is(newValue, oldValue))
1427
- return;
1428
- let propName = myfx.camelCase(attributeName);
1429
- let propDef = DefinitionPropMap.get(this.constructor.name)[propName];
1430
- if (isBooleanProp(propDef.type)) {
1431
- let v = myfx.isNull(newValue) ? false : getBooleanValue(newValue);
1432
- if (myfx.get(this, propName) === v)
1433
- return;
1434
- }
1435
- this.__attrChanged(attributeName, oldValue, newValue);
1436
- }
1437
- //********************************** 更新
1438
- /**
1439
- * 是否需要更新,可获取变更属性
1440
- * 返回true时更新
1441
- */
1442
- shouldUpdate(changed) {
1443
- return true;
1444
- }
1445
- /**
1446
- * 1. 调用render
1447
- * 2. 更新@query/all
1448
- * 3. 更新ref
1449
- * 4. 更新prop到attr的映射
1450
- * @param changed
1451
- */
1452
- updated(changed) { }
1453
- #rootEvs = {};
1454
- #nodeEvs = {};
1455
- /**
1456
- * 由监控变量调用
1457
- * @param stateKey
1458
- * @param ov
1459
- * @param rootStateKey 如果是对象内部属性变更,会返回根属性名
1460
- * @returns
1461
- */
1462
- _notify(ov, chain, subNewValue, subOldValue) {
1463
- let varPath = [];
1464
- for (let i = 0; i < chain.length; i++) {
1465
- const seg = chain[i];
1466
- varPath.push(seg);
1467
- let v = myfx.get(this, varPath);
1468
- let pathStr = _toUpdatePath(varPath);
1469
- this.#updateSources[pathStr] = { value: v, chain: pathStr === PROP_NAME_SLOTS ? [PROP_NAME_SLOTS] : varPath, oldValue: ov, end: varPath.length === chain.length, subNewValue, subOldValue };
1470
- }
1471
- if (!this.isMounted) {
1472
- console.debug('target update...', this.tagName);
1473
- this.#updateViewImmediately = true;
1474
- return;
1475
- }
1476
- Queue.pushNext(this.#updatedD);
1477
- }
1478
- _requestWatchUpdate(newValue, oldValue, fullPath, rootObjNew, rootObjOld) {
1479
- this._watchKeys?.forEach(wk => {
1480
- if (fullPath === wk ||
1481
- (myfx.startsWith(wk, fullPath + '.') && !Object.is(myfx.get(this._getPrivateData(), wk), myfx.get(newValue, wk))) ||
1482
- (myfx.startsWith(fullPath, wk + '.') && this._watchKeysDeep.includes(wk) && !Object.is(myfx.get(this._getPrivateData(), wk), myfx.get(newValue, wk)))) {
1483
- myfx.concat(myfx.toArray(this._watchUpdateMap[wk]), myfx.toArray(this._watchDeepUpdateMap[wk])).forEach(fn => {
1484
- if (!fn)
1485
- return;
1486
- if (this._watchKeysOnceMap.get(wk) === true)
1487
- return;
1488
- this._watchUpdateArgsInNextTick.set(fn, {
1489
- newValue, oldValue, chain: fullPath.split('.'), rootObjNew, rootObjOld, fullMatch: wk === fullPath
1490
- });
1491
- this._watchUpdateSetInNextTick.add(fn);
1492
- if (this._watchKeysOnceMap.has(wk))
1493
- this._watchKeysOnceMap.set(wk, true);
1494
- });
1495
- }
1496
- });
1497
- }
1498
- _requestComputedUpdate(fullPath) {
1499
- if (this._computedUpdateDeps?.has(fullPath)) {
1500
- this._computedUpdateDeps.get(fullPath)?.forEach(fn => {
1501
- this._computedUpdateSetInNextTick.add(fn);
1502
- });
1503
- }
1504
- }
1505
- #update() {
1506
- if (myfx.size(this.#updateSources) < 1)
1507
- return;
1508
- if (!this.isMounted)
1509
- return;
1510
- const changed = this.#updateSources;
1511
- this.#updateSources = {};
1512
- let toBreak = !this.shouldUpdate(changed);
1513
- if (toBreak)
1514
- return;
1515
- //update decorators
1516
- let ary = DefinitionDecoratorMap.get(this.constructor.name) ?? DefinitionDecoratorMap.get(_getSuper(this.constructor).name);
1517
- ary && ary.sort((a, b) => b.priority - a.priority).forEach(dw => {
1518
- dw.updated(this, changed);
1519
- });
1520
- //1. filter update point
1521
- let toUpdateCss = false;
1522
- let toUpdateView = false;
1523
- let toUpdateUps = new Set();
1524
- myfx.each(changed, (x, k) => {
1525
- if (this.__updateCssDeps?.includes(k)) {
1526
- toUpdateCss = true;
1527
- }
1528
- if (!toUpdateView && this.__updateViewDeps?.includes(k)) {
1529
- toUpdateView = true;
1530
- }
1531
- if (this.__updateSubViewDeps?.has(k)) {
1532
- let ups = this.__updateSubViewDeps.get(k);
1533
- if (ups)
1534
- toUpdateUps = toUpdateUps.union(ups);
1535
- }
1536
- });
1537
- //update watch
1538
- this._watchUpdateSetInNextTick?.forEach((fn) => {
1539
- let { newValue, oldValue, chain, rootObjNew, rootObjOld, fullMatch } = this._watchUpdateArgsInNextTick.get(fn);
1540
- let nv = fullMatch ? newValue : rootObjNew;
1541
- let ov = fullMatch ? oldValue : rootObjOld;
1542
- fn.call(this, nv, ov, chain, newValue, oldValue);
1543
- });
1544
- this._watchUpdateSetInNextTick?.clear();
1545
- this._watchUpdateArgsInNextTick?.clear();
1546
- // update computed
1547
- this._computedUpdateSetInNextTick?.forEach(fn => {
1548
- let k = myfx.get(fn, 'key');
1549
- let oldValue = this.#data[k];
1550
- let newValue = fn.call(this);
1551
- if (!myfx.isObject(newValue) && newValue === oldValue)
1552
- return;
1553
- this.#data[k] = newValue;
1554
- this._notify(oldValue, [k]);
1555
- });
1556
- this._computedUpdateSetInNextTick?.clear();
1557
- //2. update view
1558
- if (this.#renderRoot?.deref()) {
1559
- if (toUpdateView) {
1560
- console.debug('update view....', this.constructor.name);
1561
- updateView(this.render(), this, this.__updateTree);
1562
- }
1563
- if (myfx.size(toUpdateUps) > 0) {
1564
- toUpdateUps.forEach(up => {
1565
- updateSubScopeView(up, this, undefined);
1566
- });
1567
- }
1568
- }
1569
- //update slot view
1570
- this.#updateSlots.forEach((v) => {
1571
- this.#updateSlot(v);
1572
- });
1573
- //update dcss
1574
- if (toUpdateCss) {
1575
- this.#updateCss();
1576
- }
1577
- this.updated(changed);
1578
- }
1579
- /**
1580
- * 1. 初始props中并未包含的属性,可从attributes取,且定义类型不是string时自动转换
1581
- * 2. 如果attributes中也未出现且必填报错
1582
- * 3. 否则设置默认值
1583
- * @returns 非props的attr集合
1584
- */
1585
- #initProps() {
1586
- let propDefs = DefinitionPropMap.get(this.constructor.name) ?? DefinitionPropMap.get(_getSuper(this.constructor).name);
1587
- let attrs = this.attributes;
1588
- let tagName = this.tagName;
1589
- let parentProps = this.#props;
1590
- let filterAttrs = {};
1591
- myfx.each(attrs, ({ name, value }) => {
1592
- if (name[0] === ATTR_PREFIX_EVENT ||
1593
- name[0] === ATTR_PREFIX_PROP ||
1594
- name[0] === ATTR_PREFIX_BOOLEAN ||
1595
- name === ATTR_REF || name === 'slot')
1596
- return;
1597
- let camelName = myfx.camelCase(name);
1598
- if (propDefs && !propDefs[camelName]) {
1599
- filterAttrs[name] = value;
1600
- }
1601
- });
1602
- this.#attrs = this.#attrs ? myfx.assign(this.#attrs, filterAttrs) : filterAttrs;
1603
- let rs = {};
1604
- if (!propDefs)
1605
- return Object.seal(rs);
1606
- let keys = Object.keys(propDefs);
1607
- let size = keys.length;
1608
- for (let i = 0; i < size; i++) {
1609
- const key = keys[i];
1610
- const kbKey = myfx.kebabCase(key);
1611
- const hasAttr = this.hasAttribute(kbKey);
1612
- let propDef = propDefs[key];
1613
- let isInited = myfx.has(parentProps, key);
1614
- let defaultVal = myfx.get(this, key);
1615
- if (!('_defaultValue' in propDef)) {
1616
- //在构造结束后
1617
- propDef._defaultValue = defaultVal;
1618
- if (!propDef.type) {
1619
- if (myfx.isUndefined(defaultVal)) {
1620
- showTagError(tagName, "Prop '" + key + "' has neither propType nor defaultValue be used for type inference");
1621
- }
1622
- let type = typeof defaultVal;
1623
- if (myfx.isArray(defaultVal))
1624
- type = 'array';
1625
- let inferredType = PropTypeMap[type];
1626
- propDef.type = inferredType;
1627
- }
1628
- }
1629
- if (propDef.hasChanged) {
1630
- if (!this._hasChangedPropOrStateMap) {
1631
- this._hasChangedPropOrStateMap = new Map();
1632
- }
1633
- this._hasChangedPropOrStateMap.set(key, propDef.hasChanged);
1634
- }
1635
- if (propDef.sync) {
1636
- if (!this._hasSyncPropSet) {
1637
- this._hasSyncPropSet = new Set();
1638
- }
1639
- this._hasSyncPropSet.add(key);
1640
- }
1641
- let val = undefined;
1642
- if (isInited) {
1643
- val = myfx.isNil(parentProps[key]) ? defaultVal : parentProps[key];
1644
- }
1645
- else {
1646
- val = defaultVal;
1647
- let attr = attrs.getNamedItem(kbKey) ||
1648
- attrs.getNamedItem(ATTR_PREFIX_PROP + kbKey);
1649
- if (attr) {
1650
- isInited = true;
1651
- val = attr.value;
1652
- }
1653
- }
1654
- //required check
1655
- let isRequired = propDef.required;
1656
- if (isRequired && !isInited) {
1657
- showTagError(tagName, "Prop '" + key + "' is required");
1658
- break;
1659
- }
1660
- val = this.#propTypeCheck(propDefs, key, val, hasAttr);
1661
- let getter = myfx.get(propDefs, [key, 'getter']);
1662
- if (getter)
1663
- getter = myfx.bind(getter, this);
1664
- let setter = myfx.get(propDefs, [key, 'setter']);
1665
- if (setter)
1666
- setter = myfx.bind(setter, this);
1667
- if (getter || setter) {
1668
- Reflect.defineProperty(this.#data, key, {
1669
- set: setter || function (v) { },
1670
- get: getter
1671
- });
1672
- }
1673
- if (propDef.attribute && myfx.isDefined(val) && !myfx.isObject(val)) {
1674
- this.#updateAttribute(propDef, key, val);
1675
- }
1676
- this.#data[key] = val;
1677
- rs[key] = val;
1678
- }
1679
- return Object.seal(rs);
1680
- }
1681
- #updateAttribute(propDef, key, val) {
1682
- let k = myfx.kebabCase(key);
1683
- let v = myfx.trim(val);
1684
- if (isBooleanProp(propDef.type)) {
1685
- v = getBooleanValue(val);
1686
- if (myfx.isBoolean(v)) {
1687
- if (v && !this.hasAttribute(k)) {
1688
- this.toggleAttribute(k, true);
1689
- }
1690
- else if (!v && this.hasAttribute(k)) {
1691
- this.toggleAttribute(k, false);
1692
- }
1693
- }
1694
- else if (this.getAttribute(k) !== v) {
1695
- this.setAttribute(k, v);
1696
- }
1697
- }
1698
- else if (this.getAttribute(k) !== v) {
1699
- this.setAttribute(k, v);
1700
- }
1701
- }
1702
- #convertValue(v, types) {
1703
- let val = v;
1704
- try {
1705
- for (let i = 0; i < types.length; i++) {
1706
- const t = types[i];
1707
- if (t === Boolean) {
1708
- val = getBooleanValue(v);
1709
- }
1710
- else if (t === Number) {
1711
- val = Number(v);
1712
- }
1713
- else if (t === String) {
1714
- val = String(v);
1715
- }
1716
- else if (t === Object || t === Array) {
1717
- val = myfx.parseJSON(v);
1718
- }
1719
- else if (t === Date) {
1720
- val = new Date(v);
1721
- }
1722
- else {
1723
- val = new t(v);
1724
- }
1725
- }
1726
- }
1727
- catch (error) {
1728
- showTagError(this.tagName, `Convert attribute error with ` + v);
1729
- }
1730
- return val;
1731
- }
1732
- //属性值检测
1733
- #propTypeCheck(propDefs, propKey, newValue, hasAttr) {
1734
- let propDef = propDefs[propKey];
1735
- if (!propDef)
1736
- return newValue;
1737
- let validator = propDef.isValid;
1738
- let expectType = propDef.type;
1739
- let expectTypeAry = myfx.isArray(expectType) ? expectType : [expectType];
1740
- let typeConverter = propDef.converter;
1741
- let val = newValue;
1742
- if (!myfx.some(expectTypeAry, (et) => et === String) && myfx.isString(val) && !myfx.isNull(val)) {
1743
- try {
1744
- val = typeConverter ? typeConverter(val) : this.#convertValue(val, expectTypeAry);
1745
- }
1746
- catch (error) {
1747
- showTagError(this.tagName, `Convert attribute '${propKey}' error with ` + val);
1748
- }
1749
- } //endif
1750
- //extra work
1751
- for (let i = 0; i < expectTypeAry.length; i++) {
1752
- const et = expectTypeAry[i];
1753
- if (et.name === 'Boolean' && hasAttr) {
1754
- val = getBooleanValue(val);
1755
- }
1756
- }
1757
- if (myfx.isNil(val)) {
1758
- return val;
1759
- }
1760
- let realType = typeof val;
1761
- let matched = myfx.isDefined(val) ? false : true;
1762
- for (let i = 0; i < expectTypeAry.length; i++) {
1763
- const et = expectTypeAry[i];
1764
- if (
1765
- //base form
1766
- myfx.test(realType, et.name, "i") ||
1767
- //object form
1768
- val instanceof et || (Object.prototype.toString.call(val) === Object.prototype.toString.call(et.prototype))) {
1769
- matched = true;
1770
- break;
1771
- }
1772
- }
1773
- if (!matched) {
1774
- showTagError(this.tagName, `Invalid prop '${propKey}'. expected '${expectTypeAry.map((t) => t.name || t)}' but got '${realType}'`);
1775
- }
1776
- if (validator) {
1777
- if (!validator.call(this, val, this.#data)) {
1778
- showTagError(this.tagName, `Invalid prop '${propKey}'. IsValid() check failed`);
1779
- }
1780
- }
1781
- return val;
1782
- }
1783
- #initStates() {
1784
- let stateDefs = DefinitionStateMap.get(this.constructor.name) ?? DefinitionStateMap.get(_getSuper(this.constructor).name);
1785
- if (stateDefs)
1786
- myfx.each(stateDefs, (def, key) => {
1787
- let stateDef = stateDefs[key];
1788
- let val = myfx.get(this, key);
1789
- if (stateDef) {
1790
- let propName = stateDef.prop;
1791
- val = propName ? myfx.cloneDeep(this.#data[propName]) : myfx.get(this, key);
1792
- }
1793
- if (stateDef.hasChanged) {
1794
- if (!this._hasChangedPropOrStateMap) {
1795
- this._hasChangedPropOrStateMap = new Map();
1796
- }
1797
- this._hasChangedPropOrStateMap.set(key, stateDef.hasChanged);
1798
- }
1799
- if (stateDef.shallow) {
1800
- if (!this._hasShallowStateSet) {
1801
- this._hasShallowStateSet = new Set();
1802
- }
1803
- this._hasShallowStateSet.add(key);
1804
- }
1805
- this.#data[key] = val;
1806
- });
1807
- }
1808
- /**
1809
- * 由外部调用,在初始化及更新时。
1810
- * @param props
1811
- * @param attrs
1812
- */
1813
- #propsReady = myfx.debounce(this.propsReady, 100);
1814
- //todo 这里需要直接修改prop
1815
- _updateProps(props) {
1816
- let propDefs = DefinitionPropMap.get(this.constructor.name);
1817
- if (!propDefs)
1818
- return;
1819
- let need2UpdateAttrs = [];
1820
- //存在attrs表示已初始化完成
1821
- myfx.each(props, (v, k) => {
1822
- let ck = myfx.camelCase(k);
1823
- let propDef = propDefs[ck];
1824
- if (!propDef)
1825
- return;
1826
- v = this.#propTypeCheck(propDefs, ck, v);
1827
- if (propDef.attribute && myfx.isDefined(v) && !myfx.isObject(v)) {
1828
- need2UpdateAttrs.push([propDef, ck, v]);
1829
- }
1830
- myfx.set(this, ck, v);
1831
- });
1832
- myfx.assign(this.#props, props);
1833
- need2UpdateAttrs.forEach(([propDef, key, v]) => {
1834
- this.#updateAttribute(propDef, key, v);
1835
- });
1836
- if (this.#props)
1837
- this.#propsReady(this.#props);
1838
- }
1839
- _wrapperProp = {};
1840
- _initProps(props, attrs) {
1841
- this.#props = myfx.merge(this.#props || {}, props);
1842
- this.#attrs = myfx.merge(this.#attrs || {}, attrs);
1843
- myfx.each(props, (v, k) => {
1844
- if (myfx.isObject(v)) {
1845
- let fromPath = OBJECT_VAR_PATH.get(v);
1846
- if (fromPath) {
1847
- let propPath = fromPath.join(PATH_SEPARATOR);
1848
- this._wrapperProp[propPath] = k;
1849
- let parentStateDefs = this.wrapperComponent ? DefinitionStateMap.get(this.wrapperComponent?.constructor.name) : null;
1850
- let parentStateKey = fromPath[0];
1851
- if (parentStateDefs && parentStateDefs[parentStateKey]) {
1852
- let propDefs = DefinitionPropMap.get(this.constructor.name);
1853
- myfx.set(propDefs, [k, 'shallow'], parentStateDefs[parentStateKey].shallow);
1854
- }
1855
- }
1856
- }
1857
- });
1858
- }
1859
- /**
1860
- * 绑定slot标签,render时调用
1861
- */
1862
- _bindSlot(slot, name, props) {
1863
- //1. 设置map
1864
- if (!this.#slotsEl[name]) {
1865
- this.#slotsEl[name] = slot;
1866
- SlotCompMap.set(slot, this);
1867
- }
1868
- this.addEvent(slot, 'slotchange', this.__onSlotChangeHook);
1869
- //3. 保存参数
1870
- if (!myfx.isEmpty(props)) {
1871
- let slotMap = this.#slotPropsMap[name];
1872
- if (!slotMap) {
1873
- slotMap = this.#slotPropsMap[name] = {};
1874
- }
1875
- slotMap.props = props;
1876
- }
1877
- }
1878
- _bindSlotHook(name, hook) {
1879
- this.#slotHooks[name] = hook;
1880
- }
1881
- //slot变量变动时触发
1882
- #updateSlots = new Set();
1883
- _updateSlot(name, propName, value) {
1884
- let slotEl = this.#slotsEl[name];
1885
- let hook = this.#slotHooks[name];
1886
- if (!hook && !slotEl)
1887
- return;
1888
- let slotMap = this.#slotPropsMap[name];
1889
- if (propName) {
1890
- if (!slotMap.props) {
1891
- slotMap.props = {};
1892
- }
1893
- slotMap.props[propName] = value;
1894
- }
1895
- if (!!hook) {
1896
- this.#updateSlots.add(name);
1897
- }
1898
- else {
1899
- //update nodes
1900
- let els = slotEl.assignedElements({ flatten: true });
1901
- for (let i = 0; i < els.length; i++) {
1902
- const el = els[i];
1903
- el.setAttribute(propName, value + '');
1904
- }
1905
- }
1906
- }
1907
- #updateSlotsAry() {
1908
- if (!this.#renderRoot)
1909
- return;
1910
- let slotKeys = myfx.keys(this.#slotsEl);
1911
- if (myfx.isEmpty(slotKeys))
1912
- return;
1913
- const cs = myfx.flatMap(this.childNodes, node => {
1914
- if (node.nodeType === Node.COMMENT_NODE)
1915
- return [];
1916
- if (node instanceof HTMLSlotElement)
1917
- return node.assignedNodes({ flatten: true });
1918
- return node;
1919
- });
1920
- let groups = myfx.groupBy(cs, node => {
1921
- if (node.nodeType === Node.TEXT_NODE && slotKeys.includes(SLOT_NAME_DEFAULT))
1922
- return SLOT_NAME_DEFAULT;
1923
- if (node instanceof Element) {
1924
- let sName = node.getAttribute('slot') || SLOT_NAME_DEFAULT;
1925
- if (slotKeys.includes(sName))
1926
- return sName;
1927
- }
1928
- });
1929
- if (myfx.isEmpty(groups)) {
1930
- this.slots = {};
1931
- return;
1932
- }
1933
- myfx.each(groups, (nodeAry, k) => {
1934
- if (!k)
1935
- return;
1936
- while (nodeAry.length > 0) {
1937
- let node = nodeAry[0];
1938
- if ((node.nodeType === Node.TEXT_NODE && myfx.isBlank(node.textContent)) ||
1939
- (node instanceof HTMLSlotElement && myfx.isEmpty(node.assignedNodes({ flatten: true })))) {
1940
- nodeAry.shift();
1941
- continue;
1942
- }
1943
- break;
1944
- }
1945
- while (nodeAry.length > 0) {
1946
- let node = myfx.last(nodeAry);
1947
- if ((node.nodeType === Node.TEXT_NODE && myfx.isBlank(node.textContent)) ||
1948
- (node instanceof HTMLSlotElement && myfx.isEmpty(node.assignedNodes({ flatten: true })))) {
1949
- nodeAry.pop();
1950
- continue;
1951
- }
1952
- break;
1953
- }
1954
- });
1955
- let rs = {};
1956
- myfx.each(groups, (v, k) => {
1957
- if (!myfx.isEmpty(v)) {
1958
- rs[k] = v;
1959
- }
1960
- });
1961
- this.slots = rs;
1962
- }
1963
- #updateSlot(name) {
1964
- let hook = this.#slotHooks[name];
1965
- if (!hook)
1966
- return;
1967
- let slotMap = this.#slotPropsMap[name];
1968
- if (!this.#data.slots)
1969
- return;
1970
- let slot = this.#data.slots[name];
1971
- //slot not ready yet
1972
- //1. 可能是if/each等指令还未插入
1973
- if (!slot)
1974
- return;
1975
- //组件通知渲染异步指令
1976
- this.renderAsync(hook, myfx.get(slotMap, 'props'));
1977
- const rc = this._asyncDirectives.get(hook);
1978
- //todo 如果要做成通用异步指令,元素必须插入到指令挂载的位置,并且slot的插入节点还要去掉注释
1979
- let nodes = rc?.buildView(hook(myfx.get(slotMap, 'props')));
1980
- let nnodes = myfx.reject(myfx.toArray(nodes), n => n.nodeType === Node.COMMENT_NODE);
1981
- if (nnodes) {
1982
- let slottedNodes = this.#slotNodes[name];
1983
- if (!myfx.isEmpty(slottedNodes)) {
1984
- for (let i = 0; i < slottedNodes.length; i++) {
1985
- const n = slottedNodes[i];
1986
- n.parentNode?.removeChild(n);
1987
- }
1988
- }
1989
- this.#slotNodes[name] = nnodes;
1990
- this.append(...nnodes);
1991
- this.#updateSlots.clear();
1992
- }
1993
- }
1994
- _asyncDirectives = new WeakMap();
1995
- renderAsync(cbk, ...args) {
1996
- }
1997
- #updateCss() {
1998
- let cssTmpls = this.styles;
1999
- cssTmpls.forEach((cssTmpl, i) => {
2000
- let cssss = this.__cssSheets[i];
2001
- let css = cssTmpl.getCss(this);
2002
- cssss.replaceSync(css);
2003
- });
2004
- }
2005
- __attrChanged(name, oldValue, newValue) {
2006
- if (!this.#inited)
2007
- return;
2008
- let observedAttrs = _getObservedAttrs(this.constructor);
2009
- if (observedAttrs.has(name)) {
2010
- let camelName = myfx.camelCase(name);
2011
- if (myfx.isNull(newValue)) {
2012
- let propDefs = DefinitionPropMap.get(this.constructor.name);
2013
- //使用默认值
2014
- if (propDefs)
2015
- newValue = propDefs[camelName]._defaultValue;
2016
- }
2017
- this._updateProps({ [camelName]: newValue });
2018
- }
2019
- }
2020
- _regWrapper(wrapperComponent) {
2021
- this.#wrapperComponent = new WeakRef(wrapperComponent);
2022
- }
2023
- _regSubViewDeps(props, up) {
2024
- if (!this.__updateSubViewDeps) {
2025
- this.__updateSubViewDeps = new Map();
2026
- }
2027
- props.forEach(prop => {
2028
- let depSet = this.__updateSubViewDeps.get(prop);
2029
- if (!depSet) {
2030
- depSet = new Set();
2031
- this.__updateSubViewDeps.set(prop, depSet);
2032
- }
2033
- depSet.add(up);
2034
- });
2035
- }
2036
- _getPrivateData() {
2037
- return this.#data;
2038
- }
2039
- ////////////////////----------------------------/////////////// APIs
2040
- /**
2041
- * 抛出自定义事件
2042
- * @param evName 事件名称
2043
- * @param args 自定义参数
2044
- */
2045
- emit(evName, arg = {}, options) {
2046
- if (options && options.event) {
2047
- arg.event = options.event;
2048
- }
2049
- arg.target = this;
2050
- this.dispatchEvent(new CustomEvent(evName, {
2051
- bubbles: myfx.get(options, "bubbles", false),
2052
- composed: myfx.get(options, "composed", false),
2053
- cancelable: true,
2054
- detail: arg,
2055
- }));
2056
- }
2057
- /**
2058
- * 在root上绑定事件
2059
- * @param evName
2060
- * @param hook
2061
- * @returns 函数钩子,用于卸载
2062
- */
2063
- on(evName, hook) {
2064
- if (!this.#rootEvs[evName]) {
2065
- this.#rootEvs[evName] = [];
2066
- }
2067
- let cbk = hook.bind(this);
2068
- this.#rootEvs[evName].push(cbk);
2069
- this.addEventListener(evName, cbk);
2070
- return cbk;
2071
- }
2072
- /**
2073
- * 从root上移除事件
2074
- * @param evName
2075
- * @param hook on函数返回的钩子,可选。为空时移除所有evName事件
2076
- */
2077
- off(evName, hook) {
2078
- if (hook) {
2079
- this.removeEventListener(evName, hook);
2080
- myfx.remove(this.#rootEvs[evName], cbk => cbk === hook);
2081
- }
2082
- else {
2083
- myfx.each(this.#rootEvs[evName], cbk => {
2084
- this.removeEventListener(evName, cbk);
2085
- });
2086
- this.#rootEvs[evName] = [];
2087
- }
2088
- }
2089
- addEvent(node, evName, hook) {
2090
- if (!this.#nodeEvs[evName]) {
2091
- this.#nodeEvs[evName] = [];
2092
- }
2093
- let cbk = hook.bind(this);
2094
- this.#nodeEvs[evName].push([cbk, new WeakRef(node)]);
2095
- node.addEventListener(evName, cbk);
2096
- return cbk;
2097
- }
2098
- removeEvent(node, evName, hook) {
2099
- if (hook) {
2100
- node.removeEventListener(evName, hook);
2101
- myfx.remove(this.#nodeEvs[evName], ([cbk]) => cbk === hook);
2102
- }
2103
- else {
2104
- myfx.each(this.#nodeEvs[evName], ([cbk]) => {
2105
- node.removeEventListener(evName, cbk);
2106
- });
2107
- this.#nodeEvs[evName] = [];
2108
- }
2109
- }
2110
- /**
2111
- * 下一帧执行
2112
- * @param cbk
2113
- */
2114
- nextTick(cbk) {
2115
- if (!this.isMounted) {
2116
- if (!this.#updateNextImmediatelyQ) {
2117
- this.#updateNextImmediatelyQ = [];
2118
- }
2119
- console.debug('target update...', this.tagName);
2120
- this.#updateNextImmediatelyQ.push(cbk);
2121
- return;
2122
- }
2123
- Queue.pushNext(cbk);
2124
- }
2125
- /**
2126
- * 强制更新一次视图
2127
- */
2128
- forceUpdate() {
2129
- myfx.each(this.#data, (v, k) => {
2130
- this.#updateSources[k] = {
2131
- value: undefined,
2132
- chain: undefined,
2133
- };
2134
- });
2135
- this.#update();
2136
- }
2137
- }
2138
-
2139
- /**
2140
- * 视图模板
2141
- * @author holyhigh2
2142
- */
2143
- class Template {
2144
- strings;
2145
- vars;
2146
- constructor(strings, vars) {
2147
- this.strings = myfx.concat(strings);
2148
- this.vars = vars;
2149
- }
2150
- //解析模板中的key
2151
- getKey() {
2152
- let vars = this.vars;
2153
- let k = '';
2154
- myfx.each(this.strings, (str, i) => {
2155
- if (EXP_KEY.test(str)) {
2156
- k = myfx.toString(vars[i]);
2157
- return false;
2158
- }
2159
- });
2160
- return k;
2161
- }
2162
- getKeys() {
2163
- let vars = this.vars;
2164
- let ks = [];
2165
- for (let i = 0; i < this.strings.length; i++) {
2166
- const str = this.strings[i];
2167
- if (EXP_KEY.test(str)) {
2168
- let k = myfx.toString(vars[i]);
2169
- ks.push(k);
2170
- }
2171
- }
2172
- if (myfx.isEmpty(ks)) {
2173
- vars.forEach(v => {
2174
- if (v instanceof Template) {
2175
- let k = v.getKey();
2176
- ks.push(k);
2177
- }
2178
- });
2179
- }
2180
- return ks;
2181
- }
2182
- /**
2183
- * 追加tmpl
2184
- * 交接处模板进行合并
2185
- * @param tmpl
2186
- */
2187
- append(tmpl) {
2188
- let lastStr = myfx.last(this.strings);
2189
- tmpl.strings.forEach((str, i) => {
2190
- if (i == 0) {
2191
- this.strings[this.strings.length - 1] = lastStr + str;
2192
- return;
2193
- }
2194
- this.strings.push(str);
2195
- });
2196
- this.vars = myfx.concat(this.vars, tmpl.vars);
2197
- return this;
2198
- }
2199
- /**
2200
- * 指定位置插入模板
2201
- * @param position 字符模板位置
2202
- * @param tmpl
2203
- * @returns
2204
- */
2205
- insert(position, tmpl) {
2206
- let firstStr = tmpl.strings.shift();
2207
- this.strings[position] += firstStr;
2208
- this.strings.splice(position + 1, 0, ...tmpl.strings);
2209
- this.vars.splice(position, 0, ...tmpl.vars);
2210
- return this;
2211
- }
2212
- getHTML(comp) {
2213
- let [html, vars] = buildHTML(comp, this);
2214
- let nodes = buildTmplate([], html, vars, comp);
2215
- return myfx.reduce(nodes, (a, v) => a + (v.outerHTML ?? ''), '');
2216
- }
2217
- /**
2218
- * 对var中的Template类型进行合并
2219
- */
2220
- flatVars(comp) {
2221
- let vars = myfx.concat(this.vars);
2222
- let l = this.strings.length - 1;
2223
- let varIndex = 0;
2224
- for (let i = 0; i <= l; i++) {
2225
- let val = myfx.get(vars, varIndex, '');
2226
- if (val instanceof Template && val.vars.length > 0) {
2227
- let [h, v] = buildHTML(comp, val);
2228
- val = h;
2229
- vars.splice(varIndex, 1, ...v);
2230
- varIndex += v.length - 1;
2231
- }
2232
- varIndex++;
2233
- }
2234
- return vars;
2235
- }
2236
- destroy() {
2237
- this.strings = this.vars = null;
2238
- }
2239
- }
2240
-
2241
- /**
2242
- * @author holyhigh2
2243
- */
2244
- /**
2245
- * 属性定义
2246
- */
2247
- exports.EnterPointType = void 0;
2248
- (function (EnterPointType) {
2249
- EnterPointType["ATTR"] = "attr";
2250
- EnterPointType["PROP"] = "prop";
2251
- EnterPointType["TEXT"] = "text";
2252
- EnterPointType["CLASS"] = "class";
2253
- EnterPointType["STYLE"] = "style";
2254
- EnterPointType["SLOT"] = "slot";
2255
- EnterPointType["TAG"] = "tag"; //在标签内但不是属性内
2256
- })(exports.EnterPointType || (exports.EnterPointType = {}));
2257
- exports.DirectiveUpdateTag = void 0;
2258
- (function (DirectiveUpdateTag) {
2259
- DirectiveUpdateTag["NONE"] = "NONE";
2260
- DirectiveUpdateTag["REMOVE"] = "REMOVE";
2261
- DirectiveUpdateTag["REPLACE"] = "REPLACE";
2262
- DirectiveUpdateTag["UPDATE"] = "UPDATE";
2263
- DirectiveUpdateTag["APPEND"] = "APPEND";
2264
- })(exports.DirectiveUpdateTag || (exports.DirectiveUpdateTag = {}));
2265
- /**
2266
- * 视图更新点
2267
- */
2268
- class UpdatePoint {
2269
- //在子视图中的平级key
2270
- key;
2271
- //表达式对应的vars位置
2272
- varIndex;
2273
- value;
2274
- //表达式所在节点,可能是元素/文本
2275
- node;
2276
- //如果在属性中,属性名
2277
- attrName;
2278
- //属性值模板
2279
- attrTmpl;
2280
- isText = false;
2281
- //是否模板
2282
- // isTmpl: boolean = false;
2283
- isDirective = false;
2284
- //是否组件
2285
- isComponent = false;
2286
- //是否组件属性
2287
- isProp = false;
2288
- //是否布尔属性
2289
- isToggleProp = false;
2290
- //是否被更新,对于 key,event,ref等属性不需要更新,仅用于占位
2291
- isPlaceholder;
2292
- __destroyed = false;
2293
- directiveOldValue;
2294
- children;
2295
- parent;
2296
- constructor(varIndex, node, attrName, attrTmpl) {
2297
- this.varIndex = varIndex;
2298
- if (node)
2299
- this.node = node;
2300
- if (attrName)
2301
- this.attrName = attrName;
2302
- if (attrTmpl) {
2303
- this.attrTmpl = attrTmpl;
2304
- }
2305
- }
2306
- static createFrom(up) {
2307
- let newUp = new UpdatePoint(up.varIndex, up.node, up.attrName, up.attrTmpl);
2308
- newUp.key = up.key;
2309
- newUp.value = up.value;
2310
- newUp.isText = up.isText;
2311
- newUp.isDirective = up.isDirective;
2312
- newUp.isComponent = up.isComponent;
2313
- newUp.isProp = up.isProp;
2314
- newUp.isToggleProp = up.isToggleProp;
2315
- newUp.isPlaceholder = up.isPlaceholder;
2316
- return newUp;
2317
- }
2318
- destroy(contextComponent) {
2319
- if (this.__destroyed)
2320
- return;
2321
- this.__destroyed = true;
2322
- let node = this.node;
2323
- let children = this.children;
2324
- let parent = this.parent;
2325
- //clean up
2326
- this.node = this.value = this.directiveOldValue = this.children = this.parent = null;
2327
- if (!node)
2328
- return;
2329
- //sup scope
2330
- parent?.children || contextComponent?.__updateTree;
2331
- // contextComponent?._unregDeps(node.deref()!)
2332
- //sub scopes
2333
- let updatePoints = children;
2334
- updatePoints?.forEach((up, i) => {
2335
- up.destroy(contextComponent);
2336
- });
2337
- if (node instanceof CompElem) {
2338
- node.destroy();
2339
- }
2340
- if (contextComponent) {
2341
- DomUtil.clear(node.deref(), contextComponent);
2342
- }
2343
- node.deref()?.remove();
2344
- }
2345
- insert(up) {
2346
- up.parent = this;
2347
- if (!this.children) {
2348
- this.children = [];
2349
- }
2350
- this.children.push(up);
2351
- }
2352
- }
2353
-
2354
- const DI_COMMENT_START_NODE_MAP = new WeakMap();
2355
- const TextOrSlotDirectiveExecutorMap = new Map();
2356
- var MovePosition;
2357
- (function (MovePosition) {
2358
- MovePosition["AFTER_BEGIN"] = "afterbegin";
2359
- })(MovePosition || (MovePosition = {}));
2360
- let newNodeMap = {};
2361
- function addNodes(adds, newTmpls, component, pointNode, newNodeMap, up) {
2362
- const combStrings = [];
2363
- const combVars = [];
2364
- const ks = [];
2365
- let addGroup = [];
2366
- let lastKey;
2367
- adds.forEach(add => {
2368
- let lastAdd = myfx.last(addGroup);
2369
- if (lastAdd) {
2370
- if (lastKey === add.prevNode) {
2371
- if (!lastAdd.group) {
2372
- lastAdd.group = [lastKey];
2373
- }
2374
- lastAdd.group.push(add.newkey);
2375
- }
2376
- else {
2377
- addGroup.push(add);
2378
- }
2379
- }
2380
- else {
2381
- addGroup.push(add);
2382
- }
2383
- lastKey = add.newkey;
2384
- let k = add.newkey;
2385
- ks.push(k);
2386
- combStrings.push('');
2387
- combVars.push(newTmpls[k]);
2388
- });
2389
- combStrings.push('');
2390
- let tmpl = new Template(combStrings, combVars);
2391
- let nodes = buildSubView(pointNode, tmpl, component, up, true);
2392
- let kMap = new Map();
2393
- nodes.forEach((n) => {
2394
- const k = n.getAttribute('key');
2395
- if (ks.includes(k)) {
2396
- kMap.set(k, true);
2397
- newNodeMap[k] = n;
2398
- }
2399
- });
2400
- return addGroup;
2401
- }
2402
- function updateDirective(pointNode, newArgs, oldArgs, executor, renderComponent, slotComponent, varChain, up) {
2403
- let rs;
2404
- let isTextOrSlot = [exports.EnterPointType.TEXT, exports.EnterPointType.SLOT].includes(myfx.get(executor, '__scope', ''));
2405
- if (isTextOrSlot) {
2406
- Collector.start();
2407
- rs = executor(pointNode, newArgs, oldArgs, { renderComponent, slotComponent, varChain });
2408
- Collector.end(renderComponent, up);
2409
- }
2410
- else {
2411
- rs = executor(pointNode, newArgs, oldArgs, { renderComponent, slotComponent, varChain });
2412
- }
2413
- if (!rs)
2414
- return;
2415
- let [tag, tmpl] = rs;
2416
- if (tag === exports.DirectiveUpdateTag.NONE)
2417
- return;
2418
- let startNode = DI_COMMENT_START_NODE_MAP.get(pointNode);
2419
- let nodes = DomUtil.getNodes(startNode, pointNode);
2420
- let updatePoints = up.children;
2421
- if (tag === exports.DirectiveUpdateTag.REMOVE) {
2422
- for (let i = 0; i < nodes.length; i++) {
2423
- const n = nodes[i];
2424
- n.remove();
2425
- if (n instanceof CompElem) {
2426
- n.destroy();
2427
- }
2428
- }
2429
- updatePoints?.forEach((up, i) => {
2430
- up.destroy(renderComponent);
2431
- });
2432
- }
2433
- else if (tag === exports.DirectiveUpdateTag.REPLACE) {
2434
- let newNodes = [];
2435
- for (let i = 0; i < nodes.length; i++) {
2436
- const n = nodes[i];
2437
- n.parentNode?.removeChild(n);
2438
- if (n instanceof CompElem) {
2439
- n.destroy();
2440
- }
2441
- }
2442
- updatePoints?.forEach((up, i) => {
2443
- up.destroy(renderComponent);
2444
- });
2445
- let nnodes = buildSubView(pointNode, tmpl, renderComponent, up, true);
2446
- newNodes = myfx.toArray(nnodes);
2447
- let fragment = document.createDocumentFragment();
2448
- fragment.append(...newNodes);
2449
- pointNode.parentNode.insertBefore(fragment, pointNode);
2450
- }
2451
- else if (tag === exports.DirectiveUpdateTag.UPDATE) {
2452
- let newKeys = {};
2453
- let nodesToUpdate;
2454
- //原节点顺序
2455
- let oldSeq = [];
2456
- let newSeq = [];
2457
- if (!tmpl) {
2458
- tmpl = new Template([], []);
2459
- }
2460
- if (myfx.isEmpty(nodes)) {
2461
- let nodes = buildSubView(pointNode, tmpl, renderComponent, up, true);
2462
- startNode.after(...nodes);
2463
- return;
2464
- }
2465
- let newTmpls = {};
2466
- if (tmpl instanceof Template) {
2467
- tmpl.vars.forEach(v => {
2468
- if (v instanceof Template) {
2469
- const k = v.getKey();
2470
- newTmpls[k] = v;
2471
- newKeys[k] = true;
2472
- newSeq.push(k);
2473
- }
2474
- });
2475
- }
2476
- //UPDATE仅处理元素节点
2477
- nodes = myfx.filter(myfx.compact(nodes), n => n.nodeType === Node.ELEMENT_NODE);
2478
- nodesToUpdate = myfx.filter(myfx.compact(myfx.toArray(nodesToUpdate)), n => n.nodeType === Node.ELEMENT_NODE);
2479
- let oldNodeMap = {};
2480
- let dupKey = '';
2481
- let keyQ = {};
2482
- for (let i = 0; i < nodes.length; i++) {
2483
- const node = nodes[i];
2484
- let treeNode = node;
2485
- let k = treeNode.getAttribute("key");
2486
- if (myfx.isNil(k))
2487
- continue;
2488
- if (oldNodeMap[k]) {
2489
- dupKey = k;
2490
- break;
2491
- }
2492
- oldNodeMap[k] = treeNode;
2493
- oldSeq.push(k);
2494
- keyQ[k] = true;
2495
- }
2496
- if (dupKey) {
2497
- showError(`${myfx.camelCase(pointNode.nodeValue)} - duplicate key '${dupKey}'`);
2498
- return;
2499
- }
2500
- let updateQ = newKeys;
2501
- //compare
2502
- let adds = [];
2503
- let dels = [];
2504
- //计算del
2505
- myfx.each(keyQ, (v, k) => {
2506
- if (!updateQ[k]) {
2507
- dels.push(k);
2508
- delete keyQ[k];
2509
- myfx.remove(oldSeq, x => x === k);
2510
- }
2511
- });
2512
- //move
2513
- let moved = false;
2514
- if (!myfx.isEmpty(newSeq)) {
2515
- let lastMoveIndex = -1;
2516
- let lastGroup = [];
2517
- let moveQueue = [];
2518
- let edgeOffset = 0;
2519
- let i = 0;
2520
- for (; i < newSeq.length; i++) {
2521
- const nodeId = newSeq[i];
2522
- let oldI = oldSeq.findIndex(c => c === nodeId);
2523
- if (oldI < 0) {
2524
- let prevKey = newSeq[i - 1];
2525
- let prev = prevKey ? oldNodeMap[prevKey] || prevKey : startNode;
2526
- //add
2527
- adds.push({ prevNode: prev, newkey: nodeId });
2528
- edgeOffset++;
2529
- continue;
2530
- }
2531
- if (oldI > -1 && oldI !== (i - edgeOffset)) {
2532
- if (lastMoveIndex < 0 || Math.abs(lastMoveIndex - oldI) === 1) {
2533
- let lastEl = myfx.last(lastGroup);
2534
- lastGroup.push({ nodeId, targetId: i === 0 ? MovePosition.AFTER_BEGIN : (lastEl ? lastEl.nodeId : newSeq[i - 1]) });
2535
- }
2536
- else {
2537
- moveQueue.push({ moveGroup: lastGroup, moveIndex: i + lastGroup.length });
2538
- lastGroup = [];
2539
- lastGroup.push({ nodeId, targetId: newSeq[i - 1] });
2540
- }
2541
- lastMoveIndex = oldI;
2542
- }
2543
- }
2544
- if (lastGroup.length > 0) {
2545
- moveQueue.push({ moveGroup: lastGroup, moveIndex: i + lastGroup.length });
2546
- }
2547
- if (moveQueue.length > 0) {
2548
- moved = true;
2549
- let vals = moveQueue.sort((a, b) => a.moveGroup.length - b.moveGroup.length);
2550
- if (vals.length < 2) {
2551
- let { moveGroup } = vals[0];
2552
- if (moveGroup.length > 1) {
2553
- let lastTId = myfx.last(moveGroup).targetId;
2554
- if (moveGroup[moveGroup.length - 2].nodeId === lastTId) {
2555
- moveGroup = myfx.initial(moveGroup);
2556
- }
2557
- }
2558
- moveGroup.forEach(({ targetId, nodeId }) => {
2559
- let srcEl = oldNodeMap[nodeId];
2560
- let target;
2561
- if (targetId === MovePosition.AFTER_BEGIN) {
2562
- target = startNode;
2563
- target.after(srcEl);
2564
- }
2565
- else if (oldNodeMap[targetId]) {
2566
- target = oldNodeMap[targetId];
2567
- target.after(srcEl);
2568
- }
2569
- });
2570
- }
2571
- else {
2572
- let lastGroupIndex = myfx.last(vals).moveIndex;
2573
- if (Math.abs(vals[vals.length - 2].moveIndex - lastGroupIndex) === 1) {
2574
- vals = myfx.initial(vals);
2575
- }
2576
- vals.forEach(({ moveGroup }) => {
2577
- moveGroup.forEach(({ targetId, nodeId }) => {
2578
- let srcEl = oldNodeMap[nodeId];
2579
- let target;
2580
- if (targetId === MovePosition.AFTER_BEGIN) {
2581
- target = startNode;
2582
- target.after(srcEl);
2583
- }
2584
- else {
2585
- target = oldNodeMap[targetId];
2586
- target.after(srcEl);
2587
- }
2588
- });
2589
- });
2590
- }
2591
- } //endif
2592
- }
2593
- //del
2594
- dels.forEach(k => {
2595
- let treeNode = oldNodeMap[k];
2596
- if (treeNode && treeNode.parentNode) {
2597
- oldNodeMap[k] = null;
2598
- treeNode.remove();
2599
- let ups = myfx.remove(updatePoints, up => up.key == k);
2600
- ups.forEach(up => up.destroy(renderComponent));
2601
- }
2602
- });
2603
- //add
2604
- let addGroup;
2605
- if (adds.length > 0) {
2606
- addGroup = addNodes(adds, newTmpls, renderComponent, pointNode, newNodeMap, up);
2607
- addGroup.forEach((v, i) => {
2608
- let k = v.newkey;
2609
- let treeNode = newNodeMap[k];
2610
- let prevNode = v.prevNode;
2611
- if (v.group) {
2612
- let fragment = document.createDocumentFragment();
2613
- fragment.append(...myfx.map(v.group, (nk) => newNodeMap[nk]));
2614
- treeNode = fragment;
2615
- }
2616
- if (prevNode === pointNode) {
2617
- prevNode.before(treeNode);
2618
- }
2619
- else if (prevNode === startNode) {
2620
- prevNode.after(treeNode);
2621
- }
2622
- else if (typeof prevNode === 'string') {
2623
- newNodeMap[prevNode].after(treeNode);
2624
- }
2625
- else {
2626
- prevNode.after(treeNode);
2627
- }
2628
- });
2629
- //release
2630
- newNodeMap = null;
2631
- newNodeMap = {};
2632
- }
2633
- //合并
2634
- if (tmpl.vars[0] instanceof Template) {
2635
- let tStrAry = [];
2636
- let tVarAry = [];
2637
- myfx.each(tmpl.vars, v => {
2638
- tVarAry.push(...v.vars);
2639
- tStrAry.push(...myfx.map(v.vars, v => '1'));
2640
- });
2641
- tStrAry.push('1');
2642
- tmpl = new Template(tStrAry, tVarAry);
2643
- }
2644
- //移动顺序
2645
- if (moved || dels.length > 0 || addGroup) {
2646
- const upGroup = myfx.groupBy(updatePoints, up => up.key);
2647
- let movedUpAry = [];
2648
- let i = 0;
2649
- newSeq.forEach(nk => {
2650
- upGroup[nk] && upGroup[nk].forEach((up) => {
2651
- up.varIndex = i++;
2652
- movedUpAry.push(up);
2653
- });
2654
- });
2655
- let redundant = myfx.except(updatePoints, movedUpAry);
2656
- redundant.forEach(up => up.destroy(renderComponent));
2657
- up.children = movedUpAry;
2658
- }
2659
- updateSubScopeView(up, renderComponent, tmpl);
2660
- }
2661
- }
2662
- let DiSn = 0;
2663
- /**
2664
- * 返回指令调用函数
2665
- * @param di
2666
- * @returns
2667
- */
2668
- function directive(fn, scopes) {
2669
- let name = fn.name || ('Di-' + DiSn++);
2670
- let sym = Symbol.for(name);
2671
- return (...args) => {
2672
- let executor = fn(...args);
2673
- if (myfx.includes(scopes, exports.EnterPointType.TEXT) || myfx.includes(scopes, exports.EnterPointType.SLOT))
2674
- TextOrSlotDirectiveExecutorMap.set(name, executor);
2675
- myfx.set(executor, '__scope', scopes[0]);
2676
- return [sym, args, executor, (scopeType) => {
2677
- if (!myfx.isEmpty(scopes) && !myfx.test(scopes.join(','), scopeType)) {
2678
- showError(`Directive '${Symbol.keyFor(sym)}' is out of scopes, expect '${scopes.join(',')}' bug got '${scopeType}'`);
2679
- return;
2680
- }
2681
- }, Collector.popDirectiveQ()];
2682
- };
2683
- }
2684
-
2685
- const ATTR_PREFIX_EVENT = "@";
2686
- const ATTR_PREFIX_PROP = ".";
2687
- const ATTR_PREFIX_BOOLEAN = "?";
2688
- const ATTR_PREFIX_REF = "*";
2689
- const ATTR_PROP_DELIMITER = ":";
2690
- const ATTR_REF = "ref";
2691
- const ATTR_KEY = "key";
2692
- const EXP_TAG_CONVERT = /(<\/?)\s*([A-Z][A-Za-z0-9]*)([\s>])/gm;
2693
- const EXP_ATTR_CONVERT = /\s+([\.?@*])?((?:[a-zA-Z]*[A-Z][^\s<>="']+))(?=[\s=>])/gm;
2694
- const EXP_ATTR_CHECK = /[.?-a-z]+\s*=\s*(['"])\s*([^='"]*<\!--c_ui-pl_df-->){2,}.*?\1/ims;
2695
- const EXP_PLACEHOLDER = /<\s*[a-z0-9-]+([^>]*<\!--c_ui-pl_df-->)*[^>]*?(?<!-)>/imgs;
2696
- const SLOT_KEY_PROPS = 'slot-props';
2697
- const HTML_TMPL_CACHE = {};
2698
- /**
2699
- * 提供渲染函数相关操作
2700
- * @author holyhigh2
2701
- */
2702
- function buildHTML(component, tmpl) {
2703
- let html = "";
2704
- let vars = myfx.concat(tmpl.vars);
2705
- let l = tmpl.strings.length - 1;
2706
- let vl = tmpl.vars.length - 1;
2707
- let varIndex = 0;
2708
- for (let i = 0; i <= l; i++) {
2709
- const str = tmpl.strings[i];
2710
- let val = myfx.get(vars, varIndex, '');
2711
- if (val instanceof Template) {
2712
- let [h, v] = buildHTML(component, val);
2713
- val = h;
2714
- vars.splice(varIndex, 1, ...v);
2715
- varIndex += v.length - 1;
2716
- }
2717
- else {
2718
- val = i > vl ? "" : PLACEHOLDER;
2719
- }
2720
- varIndex++;
2721
- html = html + str + val;
2722
- }
2723
- {
2724
- //attr check
2725
- let rs = html.match(EXP_ATTR_CHECK);
2726
- if (rs) {
2727
- let errorMsg = myfx.replaceAll(rs[0], PLACEHOLDER, '${...}');
2728
- showError(`Parse error: attribute value can be set only one interpolation —— \n ${errorMsg}`);
2729
- return ['', vars];
2730
- }
2731
- }
2732
- let i = 0;
2733
- html = html.replace(EXP_PLACEHOLDER, (a, b) => {
2734
- let rs = myfx.replaceAll(a, PLACEHOLDER, () => PLACEHOLDER.replace('-->', '') + (i++));
2735
- return rs;
2736
- });
2737
- html = html.replace(EXP_STR, '$1><').trim();
2738
- html = convertHTML(html);
2739
- return [html, vars];
2740
- }
2741
- function convertHTML(html) {
2742
- if (!myfx.isString(html))
2743
- return html + '';
2744
- //attr convert
2745
- html = html.replace(EXP_ATTR_CONVERT, (a, b, c) => {
2746
- return ` ${b ?? ''}${myfx.kebabCase(c)}`;
2747
- });
2748
- //tag convert
2749
- html = html.replace(EXP_TAG_CONVERT, (a, b, c, d) => {
2750
- let tag = DefinitionTagMap[c];
2751
- return b + tag + d;
2752
- });
2753
- return html;
2754
- }
2755
- function buildVars(component, tmpl) {
2756
- let vars = myfx.concat(tmpl.vars);
2757
- let l = tmpl.strings.length - 1;
2758
- for (let i = 0; i <= l; i++) {
2759
- let val = myfx.get(tmpl.vars, i, '');
2760
- if (val instanceof Template) {
2761
- // let [h, v] = buildHTML(component, val)
2762
- let vs = buildVars(component, val);
2763
- vars.splice(i, 1, ...vs);
2764
- }
2765
- }
2766
- return vars;
2767
- }
2768
- const PLACEHOLDER = "<!--c_ui-pl_df-->";
2769
- const PLACEHOLDER_PREFFIX = "<!--c_ui-pl_df";
2770
- const PLACEHOLDER_EXP = /<!--c_ui-pl_df\d*(-->)?/;
2771
- /**
2772
- * 构建模板为DOM结构
2773
- * @param html
2774
- */
2775
- function buildTmplate(updatePoints, html, vars, renderComponent, isDirective = false) {
2776
- const container = document.createElement("div");
2777
- container.innerHTML = html;
2778
- let evList = renderComponent._eventList;
2779
- if (!evList) {
2780
- evList = renderComponent._eventList = [];
2781
- }
2782
- //遍历dom
2783
- const nodeIterator = document.createNodeIterator(container, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT);
2784
- let currentNode;
2785
- let varIndex = 0;
2786
- let slotComponent;
2787
- let keyNode = null;
2788
- let keyVal = '';
2789
- while ((currentNode = nodeIterator.nextNode())) {
2790
- if (slotComponent && !slotComponent.contains(currentNode)) {
2791
- slotComponent = undefined;
2792
- }
2793
- if (currentNode instanceof HTMLElement || currentNode instanceof SVGElement) {
2794
- if (currentNode instanceof CompElem) {
2795
- slotComponent = currentNode;
2796
- }
2797
- let props = {};
2798
- let attrs = myfx.toArray(currentNode.attributes);
2799
- for (let i = 0; i < attrs.length; i++) {
2800
- const attr = attrs[i];
2801
- let { name, value } = attr;
2802
- //todo 这里需要修改为 data-slot-xx
2803
- if (name === SLOT_KEY_PROPS) {
2804
- // varCacheQueue && varCacheQueue.push({ type: VarType.AttrSlot, name: slotName, attrName: name })
2805
- continue;
2806
- } //endif
2807
- if (myfx.startsWith(name, PLACEHOLDER_PREFFIX)) {
2808
- let val = vars[varIndex];
2809
- //support directive only for now
2810
- if (myfx.isArray(val) && myfx.isSymbol(val[0])) {
2811
- let [, args, executor, checker, varChain] = val;
2812
- checker(exports.EnterPointType.TAG);
2813
- let po = new UpdatePoint(varIndex, new WeakRef(currentNode));
2814
- po.isDirective = true;
2815
- po.value = val;
2816
- po.isComponent = !!slotComponent;
2817
- updatePoints.push(po);
2818
- if (keyNode && keyNode?.contains(currentNode)) {
2819
- po.key = keyVal;
2820
- }
2821
- varIndex++;
2822
- executor(currentNode, args, undefined, { renderComponent, slotComponent, varChain });
2823
- }
2824
- currentNode.removeAttribute(name);
2825
- continue;
2826
- } //endif
2827
- //@event.stop.prevent.debounce
2828
- if (name[0] === ATTR_PREFIX_EVENT) {
2829
- let val;
2830
- if (PLACEHOLDER_EXP.test(value)) {
2831
- let po = new UpdatePoint(varIndex);
2832
- po.isPlaceholder = true;
2833
- if (keyNode && keyNode?.contains(currentNode)) {
2834
- po.key = keyVal;
2835
- }
2836
- updatePoints.push(po);
2837
- val = vars[varIndex];
2838
- if (!myfx.isFunction(val)) {
2839
- showTagError(currentNode.tagName, `Event '${name}' must be a function`);
2840
- continue;
2841
- }
2842
- varIndex++;
2843
- }
2844
- let evName = name.substring(1);
2845
- evList.push([evName, val, currentNode]);
2846
- currentNode.removeAttribute(name);
2847
- continue;
2848
- } //endif
2849
- if (name === ATTR_REF) {
2850
- if (PLACEHOLDER_EXP.test(value)) {
2851
- let val = vars[varIndex];
2852
- if (!(val instanceof RefObject)) {
2853
- showTagError(currentNode.tagName, `Ref must be a RefObject`);
2854
- continue;
2855
- }
2856
- let po = new UpdatePoint(varIndex);
2857
- po.isPlaceholder = true;
2858
- if (keyNode && keyNode?.contains(currentNode)) {
2859
- po.key = keyVal;
2860
- }
2861
- updatePoints.push(po);
2862
- varIndex++;
2863
- val.__setRef(new WeakRef(currentNode));
2864
- }
2865
- currentNode.removeAttribute(name);
2866
- continue;
2867
- } //endif
2868
- if (name === ATTR_KEY) {
2869
- let val = vars[varIndex];
2870
- currentNode.setAttribute(name, val);
2871
- let po = new UpdatePoint(varIndex);
2872
- po.isPlaceholder = true;
2873
- if (keyNode && keyNode?.contains(currentNode)) {
2874
- po.key = keyVal;
2875
- }
2876
- updatePoints.push(po);
2877
- varIndex++;
2878
- keyNode = currentNode;
2879
- keyVal = val;
2880
- if (updatePoints.length > 0) {
2881
- updatePoints.forEach(up => {
2882
- up.key = up.key ?? val;
2883
- });
2884
- }
2885
- continue;
2886
- } //endif
2887
- //校验变量必须是表达式
2888
- if (name[0] === ATTR_PREFIX_PROP && !PLACEHOLDER_EXP.test(value)) {
2889
- showTagError(currentNode.tagName, `Prop '${name}' must be an interpolation`);
2890
- continue;
2891
- }
2892
- if (PLACEHOLDER_EXP.test(value)) {
2893
- let val = vars[varIndex];
2894
- let po = new UpdatePoint(varIndex, new WeakRef(currentNode), name.replace(/\.|\?|@/, ''), value);
2895
- po.isComponent = !!slotComponent;
2896
- if (keyNode && keyNode?.contains(currentNode)) {
2897
- po.key = keyVal;
2898
- }
2899
- if (name[0] === ATTR_PREFIX_PROP ||
2900
- name[0] === ATTR_PREFIX_BOOLEAN ||
2901
- name[0] === ATTR_PREFIX_REF) {
2902
- if (myfx.isArray(val) && myfx.isSymbol(val[0])) {
2903
- let [, args, executor, checker, varChain] = val;
2904
- checker(exports.EnterPointType.PROP);
2905
- let attrName = name.substring(1);
2906
- executor(currentNode, args, undefined, { renderComponent, slotComponent, varChain, attrName });
2907
- po.value = val;
2908
- po.isDirective = true;
2909
- }
2910
- else if (name[0] === ATTR_PREFIX_BOOLEAN) {
2911
- po.isToggleProp = true;
2912
- po.value = !!val;
2913
- let attrName = name.substring(1);
2914
- if (po.value)
2915
- currentNode.setAttribute(attrName, val);
2916
- }
2917
- else if (name[0] === ATTR_PREFIX_REF) {
2918
- po.value = val;
2919
- let refNames = name.substring(1);
2920
- const [refNamec, prop] = refNames.split(ATTR_PROP_DELIMITER);
2921
- let refName = refNamec;
2922
- switch (prop) {
2923
- case 'camel':
2924
- refName = myfx.camelCase(refName);
2925
- break;
2926
- case 'kebab':
2927
- refName = myfx.kebabCase(refName);
2928
- break;
2929
- case 'snake':
2930
- refName = myfx.snakeCase(refName);
2931
- break;
2932
- }
2933
- po.attrName = refName;
2934
- currentNode.setAttribute(refName, val);
2935
- }
2936
- else {
2937
- if (!(currentNode instanceof CompElem) && currentNode.tagName !== 'SLOT') {
2938
- showTagError(currentNode.tagName, `Prop '${name}' can only be set on a CompElem or a slot`);
2939
- }
2940
- else {
2941
- let propName = myfx.camelCase(name.substring(1));
2942
- if (!(propName in currentNode) && currentNode.tagName !== 'SLOT') {
2943
- showTagError(currentNode.tagName, `Prop '${name}' is not defined in ${currentNode.tagName}`);
2944
- }
2945
- po.value = val;
2946
- po.isProp = true;
2947
- props[propName] = val;
2948
- }
2949
- }
2950
- currentNode.removeAttribute(name);
2951
- val = '';
2952
- }
2953
- else {
2954
- po.value = val;
2955
- let executor;
2956
- let args;
2957
- if (myfx.isArray(val) && myfx.isSymbol(val[0])) {
2958
- let type = exports.EnterPointType.ATTR;
2959
- if (name === "class") {
2960
- type = exports.EnterPointType.CLASS;
2961
- }
2962
- else if (name === "style") {
2963
- type = exports.EnterPointType.STYLE;
2964
- }
2965
- let [, ags, exec, checker] = val;
2966
- {
2967
- checker(type);
2968
- }
2969
- po.isDirective = true;
2970
- po.attrName = name;
2971
- args = ags;
2972
- executor = exec;
2973
- val = '';
2974
- }
2975
- value = myfx.replace(value, PLACEHOLDER_EXP, val);
2976
- //回填
2977
- attr.value = value;
2978
- if (myfx.isDefined(value)) {
2979
- currentNode.setAttribute(name, value);
2980
- }
2981
- executor && executor(currentNode, args, undefined, { renderComponent, slotComponent });
2982
- }
2983
- updatePoints.push(po);
2984
- varIndex++;
2985
- } //endif
2986
- } //endfor
2987
- if (currentNode instanceof CompElem) {
2988
- currentNode._regWrapper(renderComponent);
2989
- if (myfx.size(props) > 0)
2990
- currentNode._initProps(props);
2991
- }
2992
- else if (currentNode instanceof HTMLSlotElement) {
2993
- renderComponent._bindSlot(currentNode, currentNode.name || 'default', props);
2994
- }
2995
- }
2996
- else {
2997
- let comment = currentNode;
2998
- let ph = `<!--${comment.nodeValue}-->`;
2999
- if (ph !== PLACEHOLDER) {
3000
- continue;
3001
- }
3002
- let po = new UpdatePoint(varIndex, new WeakRef(currentNode));
3003
- if (keyNode && keyNode?.contains(currentNode)) {
3004
- po.key = keyVal;
3005
- }
3006
- updatePoints.push(po);
3007
- po.isComponent = !!slotComponent;
3008
- po.isText = true;
3009
- let val = vars[varIndex];
3010
- if (myfx.isArray(val) && myfx.isSymbol(val[0])) {
3011
- const diName = Symbol.keyFor(val[0]);
3012
- //插入start占位符
3013
- let startComment;
3014
- startComment = document.createComment(`compelem-${renderComponent.tagName}-${diName}-start`);
3015
- comment.parentNode.insertBefore(startComment, comment);
3016
- comment.nodeValue = `compelem-${renderComponent.tagName}-${diName}-end`;
3017
- comment._diName = diName;
3018
- DI_COMMENT_START_NODE_MAP.set(comment, startComment);
3019
- po.isDirective = true;
3020
- po.value = val;
3021
- let pType = slotComponent ? exports.EnterPointType.SLOT : exports.EnterPointType.TEXT;
3022
- let [, args, executor, checker, varChain] = val;
3023
- checker(pType);
3024
- po.directiveOldValue = [args, varChain];
3025
- Collector.start();
3026
- let tmpl = executor(comment, args, undefined, { renderComponent, slotComponent, varChain });
3027
- Collector.end(renderComponent, po);
3028
- //render
3029
- if (tmpl) {
3030
- let nodes = buildSubView(comment, tmpl[1], renderComponent, po);
3031
- let len = nodes.length;
3032
- if (nodes && len > 0) {
3033
- DomUtil.insertBefore(comment, Array.from(nodes));
3034
- }
3035
- }
3036
- val = undefined;
3037
- }
3038
- else {
3039
- po.value = val;
3040
- po.node = null;
3041
- }
3042
- varIndex++;
3043
- if (!po.isDirective) {
3044
- let text = myfx.toString(val ?? '');
3045
- let textDom = document.createTextNode(text);
3046
- comment.parentNode.insertBefore(textDom, comment);
3047
- comment.remove();
3048
- currentNode = textDom;
3049
- po.node = new WeakRef(textDom);
3050
- }
3051
- }
3052
- if (keyNode && !keyNode.contains(currentNode) && keyNode !== currentNode) {
3053
- keyNode = null;
3054
- keyVal = '';
3055
- }
3056
- }
3057
- return container.childNodes;
3058
- }
3059
- function buildView(tmpl, component) {
3060
- let updatePoints = [];
3061
- let nodes;
3062
- if (HTML_TMPL_CACHE[component.tagName]) {
3063
- let htmlTmpl = HTML_TMPL_CACHE[component.tagName];
3064
- let vars = buildVars(component, tmpl);
3065
- nodes = buildTmplate(updatePoints, htmlTmpl, vars, component);
3066
- }
3067
- else {
3068
- let [html, vars] = buildHTML(component, tmpl);
3069
- HTML_TMPL_CACHE[component.tagName] = html;
3070
- nodes = buildTmplate(updatePoints, html, vars, component);
3071
- }
3072
- component.__updateTree = updatePoints;
3073
- return nodes;
3074
- }
3075
- function buildSubView(pointNode, tmpl, component, po, bindEvent = false) {
3076
- let [html, vars] = buildHTML(component, tmpl);
3077
- let updatePoints = [];
3078
- let nodes = buildTmplate(updatePoints, html, vars, component, true);
3079
- if (bindEvent)
3080
- component.__bindEvents();
3081
- updatePoints.forEach(up => {
3082
- po.insert(up);
3083
- });
3084
- return nodes;
3085
- }
3086
- function updateView(tmpl, renderComponent, updatePoints, changedKeys) {
3087
- if (myfx.isBlank(myfx.join(tmpl.strings)))
3088
- return;
3089
- let vars = tmpl.flatVars(renderComponent);
3090
- for (let i = 0; i < updatePoints.length; i++) {
3091
- const up = updatePoints[i];
3092
- let varIndex = up.varIndex;
3093
- if (varIndex < 0)
3094
- continue;
3095
- if (up.isPlaceholder)
3096
- continue;
3097
- if (up.__destroyed)
3098
- continue;
3099
- let oldValue = up.value;
3100
- let newValue = vars;
3101
- let node = up.node.deref();
3102
- if (!node)
3103
- continue;
3104
- let indexSegs = myfx.split(varIndex, PATH_SEPARATOR);
3105
- for (let l = 0; l < indexSegs.length; l++) {
3106
- const seg = indexSegs[l];
3107
- newValue = myfx.get(newValue, seg);
3108
- if (newValue && newValue.vars && i < indexSegs.length - 1) {
3109
- newValue = newValue.vars;
3110
- }
3111
- }
3112
- //check
3113
- if (!myfx.isObject(oldValue) && oldValue === newValue)
3114
- continue;
3115
- let elNode = node;
3116
- if (up.isDirective) {
3117
- //指令
3118
- let [, oldArgs, executor, , varChain] = up.value;
3119
- if (!myfx.isArray(newValue))
3120
- continue;
3121
- let slotComponent = getSlotComponent(node, renderComponent);
3122
- let [, newArgs] = newValue;
3123
- updateDirective(node, newArgs, oldArgs, executor, renderComponent, slotComponent, varChain, up);
3124
- }
3125
- else if (up.isToggleProp) {
3126
- //布尔特性
3127
- if ((!!newValue) === oldValue)
3128
- continue;
3129
- elNode.toggleAttribute(up.attrName, !!newValue);
3130
- myfx.set(elNode, up.attrName, !!newValue);
3131
- }
3132
- else if (up.isProp) {
3133
- //子组件属性
3134
- if (!myfx.isObject(newValue) && newValue === oldValue)
3135
- continue;
3136
- //如果node是slot则触发组件的slot更新
3137
- if (node instanceof CompElem) {
3138
- node._updateProps({ [up.attrName]: newValue });
3139
- }
3140
- else if (node instanceof HTMLSlotElement) {
3141
- renderComponent._updateSlot(node.getAttribute('name') || 'default', up.attrName, newValue);
3142
- }
3143
- }
3144
- else if (up.attrName) {
3145
- //特性
3146
- if (!myfx.isEqual(oldValue, newValue)) {
3147
- switch (up.attrName) {
3148
- case 'value':
3149
- if (node instanceof HTMLInputElement) {
3150
- node.value = newValue;
3151
- break;
3152
- }
3153
- default:
3154
- node.setAttribute(up.attrName, myfx.replace(up.attrTmpl, PLACEHOLDER_EXP, newValue + ''));
3155
- }
3156
- }
3157
- }
3158
- else if (up.isText) {
3159
- let textNode = up.node;
3160
- textNode.deref().textContent = myfx.toString(newValue ?? '');
3161
- }
3162
- up.value = newValue;
3163
- } //endfor
3164
- // tmpl.destroy()
3165
- }
3166
- function updateSubScopeView(subScopeUpdatePoint, renderComponent, tmpl, changedKeys) {
3167
- if (!subScopeUpdatePoint)
3168
- return;
3169
- let node = subScopeUpdatePoint.node.deref();
3170
- const executor = TextOrSlotDirectiveExecutorMap.get(node._diName);
3171
- let slotComponent = getSlotComponent(node, renderComponent);
3172
- const [oldArgs, varChain] = subScopeUpdatePoint.directiveOldValue;
3173
- if (!tmpl) {
3174
- let rs = executor(node, subScopeUpdatePoint.value[1], oldArgs, { renderComponent, slotComponent, varChain });
3175
- if (!rs)
3176
- return;
3177
- tmpl = rs[1];
3178
- }
3179
- if (!tmpl)
3180
- return;
3181
- //合并
3182
- if (tmpl.vars[0] instanceof Template) {
3183
- let tStrAry = [];
3184
- let tVarAry = [];
3185
- myfx.each(tmpl.vars, v => {
3186
- tVarAry.push(...v.vars);
3187
- tStrAry.push(...myfx.map(v.vars, v => '1'));
3188
- });
3189
- tStrAry.push('1');
3190
- tmpl = new Template(tStrAry, tVarAry);
3191
- }
3192
- updateView(tmpl, renderComponent, subScopeUpdatePoint.children);
3193
- }
3194
- //////////////////////////////////////////////////// interfaces
3195
- /**
3196
- * 标签函数,用于构建模板
3197
- * @param strings
3198
- * @param vars
3199
- */
3200
- function html(strings, ...vars) {
3201
- return new Template(myfx.isString(strings) ? [strings] : strings, vars);
3202
- }
3203
- /**
3204
- * 标签函数,用于构建样式
3205
- * @param strings
3206
- * @param vars
3207
- */
3208
- function css(strings, ...vars) {
3209
- return new CssTemplate(myfx.isString(strings) ? [strings] : strings, vars);
3210
- }
3211
- const EXP_STR = /([a-z0-9"'])\s*>\s*</img;
3212
- class RefObject {
3213
- #ref;
3214
- get current() {
3215
- return this.#ref?.deref();
3216
- }
3217
- __setRef(ref) {
3218
- this.#ref = ref;
3219
- }
3220
- }
3221
- /**
3222
- * 使用初始值创建一个引用对象
3223
- * @param initValue
3224
- * @returns
3225
- */
3226
- function createRef() {
3227
- return new RefObject();
3228
- }
3229
-
3230
- //装饰器类型
3231
- exports.DecoratorType = void 0;
3232
- (function (DecoratorType) {
3233
- DecoratorType["CLASS"] = "class";
3234
- DecoratorType["FIELD"] = "field";
3235
- DecoratorType["METHOD"] = "method";
3236
- })(exports.DecoratorType || (exports.DecoratorType = {}));
3237
- /**
3238
- * 用于构造装饰器
3239
- * @author holyhigh2
3240
- */
3241
- class Decorator {
3242
- /**
3243
- * 优先级,越大越先执行
3244
- */
3245
- static get priority() {
3246
- return 0;
3247
- }
3248
- /**
3249
- * 构造会传递自定义参数
3250
- * @param args 自定义参数
3251
- */
3252
- // constructor(...args: any[]) { }
3253
- created(component, ...args) { }
3254
- /**
3255
- * 执行时机与组件一致
3256
- * @param component 组件实例
3257
- * @param setReactive 为实例设置响应属性,注意,仅是设置到了instance.reactiveData中并非this.key。如需实现this访问,可自行定义组件的properties
3258
- * @param args 装饰器函数参数
3259
- */
3260
- beforeMount(component, setReactive, ...args) { }
3261
- mounted(component, setReactive, ...args) { }
3262
- updated(component, changed) { }
3263
- beforeDestroy(component, ...args) { }
3264
- }
3265
-
3266
- /**
3267
- * 装饰器包装类
3268
- * 用于框架内部,表示class上的一个装饰器属性定义
3269
- * 该定义在实例初始化时会产生装饰器实例属性
3270
- */
3271
- class DecoratorWrapper {
3272
- //装饰器参数
3273
- metadata;
3274
- decorator;
3275
- key; //装饰器唯一key
3276
- priority = 0;
3277
- constructor(args, metadata, decoratorClass) {
3278
- this.metadata = metadata;
3279
- this.decorator = new decoratorClass(...args);
3280
- this.priority = myfx.get(decoratorClass, 'priority', 0);
3281
- }
3282
- dispose() {
3283
- //clean up
3284
- this.metadata = null;
3285
- this.decorator = null;
3286
- }
3287
- //在组件构造时调用
3288
- create(comp) {
3289
- //1. 校验targets
3290
- let targets = this.decorator.targets;
3291
- let decoType = undefined;
3292
- let descriptor = this.metadata[1];
3293
- if (myfx.isObject(descriptor) && myfx.isDefined(myfx.get(descriptor, 'configurable'))) {
3294
- decoType = exports.DecoratorType.METHOD;
3295
- }
3296
- else if (myfx.isUndefined(this.metadata[1])) {
3297
- decoType = exports.DecoratorType.FIELD;
3298
- }
3299
- if (myfx.isEmpty(targets) || !decoType || !targets.includes(decoType)) {
3300
- showError(`Decorator '${this.decorator.constructor.name}' is out of targets, expect '${targets.join(',')}' bug got '${decoType}'`);
3301
- return;
3302
- }
3303
- this.decorator.created(comp, ...this.metadata);
3304
- }
3305
- beforeMount(comp, setReactive) {
3306
- this.decorator.beforeMount(comp, setReactive, ...this.metadata);
3307
- }
3308
- mounted(comp, setReactive) {
3309
- this.decorator.mounted(comp, setReactive, ...this.metadata);
3310
- }
3311
- updated(comp, changed) {
3312
- this.decorator.updated(comp, changed);
3313
- }
3314
- destroy(comp) {
3315
- this.decorator.beforeDestroy(comp, ...this.metadata);
3316
- }
3317
- }
3318
- /**
3319
- * 该函数用于创建一个装饰器
3320
- * @param decoClass 装饰器构造
3321
- * @returns 装饰器函数
3322
- */
3323
- function decorator(decoClass) {
3324
- let fn = (...args) => {
3325
- return (...metadata) => {
3326
- let ctor = metadata[0].constructor;
3327
- let ary = DefinitionDecoratorMap.get(ctor.name); // ctor[_DecoratorsKey]
3328
- if (!DefinitionDecoratorMap.has(ctor.name)) {
3329
- //继承父类
3330
- let proto = Object.getPrototypeOf(ctor);
3331
- ary = proto ? myfx.concat(DefinitionDecoratorMap.get(proto.name) ?? []) : [];
3332
- DefinitionDecoratorMap.set(ctor.name, ary);
3333
- }
3334
- let dw = new DecoratorWrapper(args, metadata.splice(1), decoClass);
3335
- ary?.push(dw);
3336
- return dw;
3337
- };
3338
- };
3339
- return fn;
3340
- }
3341
- function decoratorWithNoArgs(decoClass) {
3342
- let fn = (...metadata) => {
3343
- if (!metadata || metadata.length < 1)
3344
- return;
3345
- let ctor = metadata[0].constructor;
3346
- let ary = DefinitionDecoratorMap.get(ctor.name); // ctor[_DecoratorsKey]
3347
- if (!DefinitionDecoratorMap.has(ctor.name)) {
3348
- //继承父类
3349
- let proto = Object.getPrototypeOf(ctor);
3350
- ary = proto ? myfx.concat(DefinitionDecoratorMap.get(proto.name) ?? []) : [];
3351
- DefinitionDecoratorMap.set(ctor.name, ary);
3352
- }
3353
- let dw = new DecoratorWrapper([], metadata.splice(1), decoClass);
3354
- ary?.push(dw);
3355
- return dw;
3356
- };
3357
- return fn;
3358
- }
3359
-
3360
- function computed(target, propertyKey, descriptor) {
3361
- if (!descriptor.get) {
3362
- showError(`Computed '${propertyKey}' must be a getter`);
3363
- }
3364
- if (!DefinitionComputedMap.has(target.constructor.name)) {
3365
- DefinitionComputedMap.set(target.constructor.name, {});
3366
- }
3367
- DefinitionComputedMap.get(target.constructor.name)[propertyKey] = descriptor.get;
3368
- }
3369
-
3370
- /**
3371
- * 定义防抖函数
3372
- * 同时会创建一个以 _$__ 结尾的非防抖版本
3373
- * @example
3374
- * @debounced(50, true)
3375
- *
3376
- * @param wait 抖动间隔,单位ms
3377
- * @param immediate 立即执行
3378
- */
3379
- class DebouncedDecorator extends Decorator {
3380
- static get priority() {
3381
- return Number.MAX_VALUE;
3382
- }
3383
- created(component, fieldName, ...args) {
3384
- let fn = myfx.get(component, fieldName);
3385
- myfx.set(component, fieldName, myfx.debounce(fn, this.wait, this.immediate));
3386
- myfx.set(component, fieldName + '_$__', fn);
3387
- }
3388
- beforeDestroy(component, fieldName) {
3389
- myfx.set(component, fieldName, null);
3390
- myfx.set(component, fieldName + '_$__', null);
3391
- }
3392
- get targets() {
3393
- return [exports.DecoratorType.METHOD];
3394
- }
3395
- wait;
3396
- immediate;
3397
- constructor(wait, immediate = false) {
3398
- super();
3399
- this.wait = wait;
3400
- this.immediate = immediate;
3401
- }
3402
- }
3403
- const debounced = decorator(DebouncedDecorator);
3404
-
3405
- /**
3406
- * 绑定非视图事件,如window/document等
3407
- * @param eventName 事件名,含修饰参数。同视图模板中的事件名
3408
- * @param eventTarget 事件绑定目标,默认this
3409
- */
3410
- function event(eventName, eventTarget) {
3411
- return (target, name, descriptor) => {
3412
- if (!DefinitionCompEventMap.has(target.constructor.name)) {
3413
- let mixinEvents = [];
3414
- let parentCtor = target.constructor;
3415
- while ((parentCtor = _getSuper(parentCtor)) !== CompElem) {
3416
- mixinEvents = myfx.concat(mixinEvents, DefinitionCompEventMap.get(parentCtor.name) ?? []);
3417
- }
3418
- DefinitionCompEventMap.set(target.constructor.name, mixinEvents);
3419
- }
3420
- DefinitionCompEventMap.get(target.constructor.name)?.push({ name: eventName, targetFn: eventTarget, fnName: name });
3421
- };
3422
- }
3423
-
3424
- /**
3425
- * 定义一次性函数
3426
- * 同时会创建一个以 _$__ 结尾的非一次性版本
3427
- * @example
3428
- * @onced
3429
- *
3430
- */
3431
- class OncedDecorator extends Decorator {
3432
- static get priority() {
3433
- return Number.MAX_VALUE;
3434
- }
3435
- created(component, classProto, fieldName, ...args) {
3436
- let fn = myfx.bind(myfx.get(component, fieldName), component);
3437
- myfx.set(component, fieldName, myfx.once(fn));
3438
- myfx.set(component, fieldName + '_$__', fn);
3439
- }
3440
- beforeDestroy(component, fieldName) {
3441
- myfx.set(component, fieldName, null);
3442
- myfx.set(component, fieldName + '_$__', null);
3443
- }
3444
- get targets() {
3445
- return [exports.DecoratorType.METHOD];
3446
- }
3447
- }
3448
- const onced = decorator(OncedDecorator);
3449
-
3450
- /**
3451
- * 缓存策略
3452
- */
3453
- exports.QueryCache = void 0;
3454
- (function (QueryCache) {
3455
- QueryCache["ONCE"] = "once";
3456
- })(exports.QueryCache || (exports.QueryCache = {}));
3457
- const CacheMap = new WeakMap();
3458
- /**
3459
- * css查询装饰器
3460
- * @example
3461
- * @query('l-popup', QueryCache.ONCE)
3462
- */
3463
- class QueryDecorator extends Decorator {
3464
- static get priority() {
3465
- return Number.MAX_VALUE;
3466
- }
3467
- get targets() {
3468
- return [exports.DecoratorType.FIELD];
3469
- }
3470
- selector;
3471
- cache;
3472
- constructor(selector, cache) {
3473
- super();
3474
- this.selector = selector;
3475
- this.cache = cache;
3476
- }
3477
- static getKey(selector) {
3478
- return selector;
3479
- }
3480
- getter(component) {
3481
- let el = component?.shadowRoot?.querySelector(this.selector);
3482
- let cMap = CacheMap.get(component);
3483
- if (!cMap) {
3484
- cMap = new Map();
3485
- CacheMap.set(component, cMap);
3486
- }
3487
- cMap.set(this.selector, el);
3488
- }
3489
- mounted(component, setReactive, fieldName, ...args) {
3490
- const that = this;
3491
- let wk = new WeakRef(component);
3492
- Reflect.defineProperty(component, fieldName, {
3493
- configurable: true,
3494
- get() {
3495
- let ctx = wk.deref();
3496
- if (CacheMap.has(ctx) && CacheMap.get(ctx)?.has(that.selector) && that.cache === exports.QueryCache.ONCE) {
3497
- return CacheMap.get(ctx)?.get(that.selector);
3498
- }
3499
- that.getter(ctx);
3500
- return CacheMap.get(ctx)?.get(that.selector);
3501
- }
3502
- });
3503
- }
3504
- beforeDestroy(component, fieldName) {
3505
- CacheMap.get(component)?.clear();
3506
- CacheMap.delete(component);
3507
- }
3508
- updated(component, changed) {
3509
- if (this.cache === exports.QueryCache.ONCE)
3510
- return;
3511
- this.getter(component);
3512
- }
3513
- }
3514
- class QueryAllDecorator extends QueryDecorator {
3515
- getter(component) {
3516
- let el = component.shadowRoot?.querySelectorAll(this.selector);
3517
- let cMap = CacheMap.get(component);
3518
- if (!cMap) {
3519
- cMap = new Map();
3520
- CacheMap.set(component, cMap);
3521
- }
3522
- cMap.set(this.selector, el);
3523
- }
3524
- }
3525
- const query = decorator(QueryDecorator);
3526
- const queryAll = decorator(QueryAllDecorator);
3527
-
3528
- function state(options) {
3529
- if (arguments.length === 1) {
3530
- return (target, stateKey) => {
3531
- defineState(target, stateKey, options);
3532
- };
3533
- }
3534
- let target = arguments[0], stateKey = arguments[1];
3535
- defineState(target, stateKey, { prop: "" });
3536
- }
3537
- function defineState(target, stateKey, options) {
3538
- if (!DefinitionStateMap.has(target.constructor.name)) {
3539
- const mixinStates = {};
3540
- let parentCtor = target.constructor;
3541
- while ((parentCtor = _getSuper(parentCtor)) !== CompElem) {
3542
- myfx.merge(mixinStates, DefinitionStateMap.get(parentCtor.name) ?? {});
3543
- }
3544
- DefinitionStateMap.set(target.constructor.name, mixinStates);
3545
- }
3546
- options.shallow = options.shallow || false;
3547
- myfx.set(DefinitionStateMap.get(target.constructor.name), stateKey, options);
3548
- }
3549
- /**
3550
- * 同@state装饰器,但可用于构造器中调用
3551
- * @param ctor 类构造函数
3552
- * @param stateKey state 名称
3553
- * @param options
3554
- */
3555
- function makeState(ctor, stateKey, options) {
3556
- defineState(ctor.prototype, stateKey, options || { prop: "" });
3557
- }
3558
-
3559
- /**
3560
- * class用注解,用于自动注册自定义组件
3561
- * @param name 自定义组件名称
3562
- */
3563
- function tag(name) {
3564
- return (target) => {
3565
- if (target) {
3566
- DefinitionTagMap[target.name] = name;
3567
- customElements.define(name, target);
3568
- }
3569
- };
3570
- }
3571
-
3572
- /**
3573
- * 定义节流函数
3574
- * 同时会创建一个以 _$__ 结尾的非节流版本
3575
- * @example
3576
- * @throttled(50, true)
3577
- *
3578
- * @param wait 抖动间隔,单位ms
3579
- */
3580
- class ThrottledDecorator extends Decorator {
3581
- static get priority() {
3582
- return Number.MAX_VALUE;
3583
- }
3584
- created(component, fieldName, ...args) {
3585
- let fn = myfx.get(component, fieldName);
3586
- myfx.set(component, fieldName, myfx.throttle(fn, this.wait));
3587
- myfx.set(component, fieldName + '_$__', fn);
3588
- }
3589
- beforeDestroy(component, fieldName) {
3590
- myfx.set(component, fieldName, null);
3591
- myfx.set(component, fieldName + '_$__', null);
3592
- }
3593
- get targets() {
3594
- return [exports.DecoratorType.METHOD];
3595
- }
3596
- wait;
3597
- constructor(wait) {
3598
- super();
3599
- this.wait = wait;
3600
- }
3601
- }
3602
- const throttled = decorator(ThrottledDecorator);
3603
-
3604
- /**
3605
- * 监控prop/state变量值变化
3606
- * @param source 变量路径支持多级路径
3607
- * @param options
3608
- * @returns
3609
- */
3610
- function watch(source, options) {
3611
- return (target, name) => {
3612
- if (!DefinitionWatchMap.has(target.constructor.name)) {
3613
- const watchMap = {};
3614
- let parentCtor = target.constructor;
3615
- while ((parentCtor = _getSuper(parentCtor)) !== CompElem) {
3616
- if (DefinitionWatchMap.has(parentCtor.name)) {
3617
- let parentMap = DefinitionWatchMap.get(parentCtor.name);
3618
- myfx.each(parentMap, (list, k) => {
3619
- watchMap[k] = list;
3620
- });
3621
- }
3622
- }
3623
- DefinitionWatchMap.set(target.constructor.name, watchMap);
3624
- }
3625
- const sources = myfx.isArray(source) ? source : [source];
3626
- sources.forEach(src => {
3627
- let srcList = DefinitionWatchMap.get(target.constructor.name)[src];
3628
- if (!myfx.isArray(srcList)) {
3629
- srcList = [];
3630
- DefinitionWatchMap.get(target.constructor.name)[src] = srcList;
3631
- }
3632
- srcList.push({ source: src, options, handler: target[name] });
3633
- });
3634
- };
3635
- }
3636
-
3637
- const Ignores = ['key'];
3638
- /**
3639
- * 绑定属性到节点上,如果节点是组件会使用in操作符判断是否props
3640
- * @param styles 对象/数组/字符串
3641
- */
3642
- const bind = directive(function Bind(obj) {
3643
- return (pointNode, [obj], oldArgs) => {
3644
- let el = pointNode;
3645
- if (oldArgs) {
3646
- myfx.each(obj, (v, k) => {
3647
- el.setAttribute(k, v);
3648
- });
3649
- return;
3650
- }
3651
- if (el instanceof CompElem) {
3652
- //判断是否prop
3653
- let props = {};
3654
- let attrs = {};
3655
- let propDefs = DefinitionPropMap.get(el.constructor.name);
3656
- myfx.each(obj, (v, k) => {
3657
- if (Ignores.includes(k))
3658
- return;
3659
- let ck = myfx.camelCase(k);
3660
- let propDef = propDefs ? propDefs[ck] : undefined;
3661
- if (propDef) {
3662
- props[k] = v;
3663
- }
3664
- else {
3665
- attrs[k] = v + '';
3666
- }
3667
- });
3668
- el._initProps(props, attrs);
3669
- }
3670
- else {
3671
- myfx.each(obj, (v, k) => {
3672
- el.setAttribute(k, v);
3673
- });
3674
- }
3675
- };
3676
- }, [exports.EnterPointType.TAG]);
3677
-
3678
- const ClassLastMap = new WeakMap();
3679
- /**
3680
- * 根据变量内容自动插入class,仅能用于class属性
3681
- * @param styles 对象/数组/字符串
3682
- */
3683
- const classes = directive(function Classes(clazz) {
3684
- return (pointNode, [clazz], oldArgs, { renderComponent }) => {
3685
- let rs = [];
3686
- if (myfx.isArray(clazz)) {
3687
- rs = myfx.compact(clazz);
3688
- }
3689
- else if (myfx.isObject(clazz)) {
3690
- rs = myfx.flatMap(clazz, (v, k) => v ? k : []);
3691
- }
3692
- else if (myfx.isString(clazz)) {
3693
- rs = clazz.split(' ');
3694
- }
3695
- if (rs.length < 1 && !oldArgs)
3696
- return;
3697
- let el = pointNode;
3698
- if (ClassLastMap.get(el) && ClassLastMap.get(el).length === rs.length && myfx.isMatch(ClassLastMap.get(el), rs))
3699
- return;
3700
- let lastCls = ClassLastMap.get(el);
3701
- myfx.each(lastCls, (cls) => {
3702
- el.classList.remove(cls);
3703
- });
3704
- myfx.each(rs, cls => {
3705
- el.classList.add(cls);
3706
- });
3707
- lastCls = myfx.concat(rs);
3708
- ClassLastMap.set(el, lastCls);
3709
- };
3710
- }, [exports.EnterPointType.CLASS]);
3711
-
3712
- const LastValueMap = new WeakMap();
3713
- const LastTmplMap$1 = new WeakMap();
3714
- /**
3715
- * 循环列表并自动优化列表更新
3716
- * foreach循环的只能是节点,且必须有key属性。非节点元素会被过滤掉
3717
- * 使用序号作为key时可能会导致异常问题
3718
- */
3719
- const forEach = directive(function ForEach(value, cbk) {
3720
- return (pointNode, newArgs, oldArgs, { varChain }) => {
3721
- let el = pointNode;
3722
- let lastRenderTmpl = comboTmpl(newArgs[0], newArgs[1], el);
3723
- if (oldArgs && oldArgs[0]) {
3724
- //更新
3725
- const lastAry = LastValueMap.get(el);
3726
- // const lastRenderTmpl = LastTmplMap.get(el)
3727
- let startNode = DI_COMMENT_START_NODE_MAP.get(pointNode);
3728
- let nodes = DomUtil.getNodes(startNode, pointNode);
3729
- if (myfx.isEmpty(nodes) && (!newArgs || myfx.isEmpty(newArgs[0])))
3730
- return [exports.DirectiveUpdateTag.NONE, lastRenderTmpl];
3731
- if (lastAry && myfx.isMatch(lastAry, newArgs[0]) && lastAry.length === newArgs[0].length)
3732
- return [exports.DirectiveUpdateTag.NONE, lastRenderTmpl];
3733
- }
3734
- LastValueMap.set(el, myfx.clone(newArgs[0]));
3735
- if (oldArgs) {
3736
- return [exports.DirectiveUpdateTag.UPDATE, lastRenderTmpl];
3737
- }
3738
- return [exports.DirectiveUpdateTag.APPEND, lastRenderTmpl];
3739
- };
3740
- }, [exports.EnterPointType.TEXT, exports.EnterPointType.SLOT]);
3741
- function comboTmpl(value, cbk, el) {
3742
- //1. 产生模板
3743
- let tmpls = myfx.map(value, (v, k) => {
3744
- return cbk(v, k);
3745
- });
3746
- if (tmpls.length < 1) {
3747
- let lastRenderTmpl = new Template([], []);
3748
- LastTmplMap$1.set(el, lastRenderTmpl);
3749
- return lastRenderTmpl;
3750
- }
3751
- //2. 检查 & 合并模板
3752
- let keyAry = [];
3753
- let strs = [];
3754
- const combStrings = [];
3755
- const combVars = [];
3756
- for (let l = 0; l < tmpls.length; l++) {
3757
- const tmpl = tmpls[l];
3758
- let lastStr = myfx.last(strs);
3759
- let vars = tmpl.vars;
3760
- let hasNoKey = true;
3761
- let tmplStrs = tmpl.strings;
3762
- for (let i = 0; i < tmplStrs.length; i++) {
3763
- const str = tmplStrs[i];
3764
- if (EXP_KEY.test(str)) {
3765
- let key = vars[i] + '';
3766
- if (keyAry.includes(key)) {
3767
- showError(`forEach - duplicate key '${key}'`);
3768
- return;
3769
- }
3770
- keyAry.push(key);
3771
- hasNoKey = false;
3772
- }
3773
- if (i == 0 && lastStr) {
3774
- strs[strs.length - 1] = lastStr + str;
3775
- continue;
3776
- }
3777
- strs.push(str);
3778
- }
3779
- if (hasNoKey) {
3780
- showError("forEach - missing 'key' prop");
3781
- return;
3782
- }
3783
- let lastVar = myfx.last(combStrings);
3784
- if (lastVar && tmplStrs.length > 0) {
3785
- combStrings[combStrings.length - 1] = myfx.trim(lastVar) + tmplStrs.shift();
3786
- }
3787
- combStrings.push('');
3788
- combVars.push(tmpl);
3789
- }
3790
- combStrings.push('');
3791
- let lastRenderTmpl = new Template(combStrings, combVars);
3792
- LastTmplMap$1.set(el, lastRenderTmpl);
3793
- return lastRenderTmpl;
3794
- }
3795
-
3796
- let compiler = document.createElement('div');
3797
- /**
3798
- * 向指定文本位置插入指定HTML内容
3799
- * @param htmlStr html内容
3800
- */
3801
- const htmlC = directive(function HtmlC(htmlStr) {
3802
- return (pointNode, newArgs, oldArgs, { renderComponent, slotComponent }) => {
3803
- if (oldArgs && newArgs[0] == oldArgs[0])
3804
- return;
3805
- if (myfx.isNil(newArgs[0]))
3806
- return;
3807
- compiler.innerHTML = convertHTML(newArgs[0]);
3808
- pointNode.after(...compiler.childNodes);
3809
- };
3810
- }, [exports.EnterPointType.TEXT, exports.EnterPointType.SLOT]);
3811
-
3812
- /**
3813
- * 向元素中插入指定HTML内容
3814
- * 注意,应用该指令的元素内部不应再出现表达式,否则会导致异常显示
3815
- * @param htmlStr html内容
3816
- */
3817
- const htmlD = directive(function HtmlD(htmlStr) {
3818
- return (pointNode, newArgs, oldArgs, { renderComponent, slotComponent }) => {
3819
- if (oldArgs && newArgs[0] == oldArgs[0])
3820
- return;
3821
- if (myfx.isNil(newArgs[0]))
3822
- return;
3823
- pointNode.innerHTML = convertHTML(newArgs[0]);
3824
- };
3825
- }, [exports.EnterPointType.TAG]);
3826
-
3827
- const LastTmplMap = new WeakMap();
3828
- /**
3829
- * 条件为真时返回参数1,否则返回参数2,仅能用于文本节点
3830
- * @param condition 条件
3831
- * @param tmpl 模板
3832
- */
3833
- const ifElse = directive(function IfElse(condition, ifTmpl, elseTmpl) {
3834
- return (pointNode, [condi, ifTmpl, elseTmpl], oldArgs, { renderComponent }) => {
3835
- let el = pointNode;
3836
- if (oldArgs) {
3837
- //更新
3838
- if (!!condi === !!oldArgs[0]) {
3839
- let tmpl = LastTmplMap.get(el);
3840
- return [exports.DirectiveUpdateTag.NONE, tmpl.call(renderComponent, condi)];
3841
- }
3842
- let tmpl = condi ? ifTmpl : elseTmpl;
3843
- LastTmplMap.set(el, tmpl);
3844
- return [exports.DirectiveUpdateTag.REPLACE, tmpl.call(renderComponent, condi)];
3845
- }
3846
- else {
3847
- let tmpl = condi ? ifTmpl : elseTmpl;
3848
- LastTmplMap.set(el, tmpl);
3849
- return [exports.DirectiveUpdateTag.APPEND, tmpl.call(renderComponent, condi)];
3850
- }
3851
- };
3852
- }, [exports.EnterPointType.TEXT, exports.EnterPointType.SLOT]);
3853
-
3854
- /**
3855
- * 条件为真时返回内容,仅能用于文本节点
3856
- * @param condition 条件
3857
- * @param tmpl 模板
3858
- */
3859
- const ifTrue = directive(function IfTrue(condition, tmplFn) {
3860
- return (pointNode, [condi, render], oldArgs) => {
3861
- if (oldArgs) {
3862
- //更新
3863
- if (condi === oldArgs[0])
3864
- return [exports.DirectiveUpdateTag.NONE, condi ? render() : html ``];
3865
- if (condi) {
3866
- return [exports.DirectiveUpdateTag.REPLACE, condi ? render() : html ``];
3867
- }
3868
- return [exports.DirectiveUpdateTag.REMOVE];
3869
- }
3870
- else {
3871
- return [exports.DirectiveUpdateTag.APPEND, condi ? render() : html ``];
3872
- }
3873
- };
3874
- }, [exports.EnterPointType.TEXT, exports.EnterPointType.SLOT]);
3875
-
3876
- exports.ModelTriggerType = void 0;
3877
- (function (ModelTriggerType) {
3878
- ModelTriggerType["CHANGE"] = "change";
3879
- ModelTriggerType["INPUT"] = "input";
3880
- })(exports.ModelTriggerType || (exports.ModelTriggerType = {}));
3881
- /**
3882
- * 实现双向绑定(仅支持静态路径,动态增加的属性路径无法识别)
3883
- * 当用于组件时,监控 @update:value 事件
3884
- * 当用于元素时,
3885
- * - 对于 input/textarea 监控 @input,并设置 value 属性
3886
- * - 对于 checkbox/radio 监控 @change,并设置 checked 属性
3887
- * - 对于 select 监控 @change,并设置 value 属性
3888
- * @param modelValue 双向绑定的组件变量
3889
- * @param updateProp 绑定模型变更时的监控属性,默认 value
3890
- * @param modelProp 当初始模型路径不存在时可指定路径
3891
- */
3892
- const model = directive(function Model(modelValue, updateProp = 'value', modelProp) {
3893
- return (pointNode, [modelValue, updateProp, modelProp], oldArgs, { varChain, renderComponent }) => {
3894
- updateProp = updateProp ?? 'value';
3895
- const node = pointNode;
3896
- if (oldArgs) {
3897
- const oldValue = oldArgs[0];
3898
- const newValue = modelValue;
3899
- let nodeValue = myfx.get(node, updateProp);
3900
- if (!myfx.isObject(newValue) && Object.is(newValue, oldValue) && Object.is(nodeValue, newValue))
3901
- return;
3902
- if (node instanceof CompElem) {
3903
- node._updateProps({ [updateProp]: newValue });
3904
- }
3905
- else if (node instanceof HTMLTextAreaElement || node instanceof HTMLSelectElement) {
3906
- node.setAttribute(updateProp, newValue + '');
3907
- if (node instanceof HTMLSelectElement) {
3908
- let opt = myfx.find(node.querySelectorAll('option'), n => n.value == newValue);
3909
- if (opt) {
3910
- opt.selected = true;
3911
- }
3912
- }
3913
- }
3914
- else if (node instanceof HTMLInputElement) {
3915
- if (node.value == newValue)
3916
- return;
3917
- switch (node.type) {
3918
- case 'checkbox':
3919
- case 'radio':
3920
- if (!!newValue) {
3921
- node.setAttribute('checked', '');
3922
- }
3923
- else {
3924
- node.removeAttribute('checked');
3925
- }
3926
- break;
3927
- case 'text':
3928
- case 'email':
3929
- case 'number':
3930
- case 'password':
3931
- case 'search':
3932
- case 'tel':
3933
- case 'url':
3934
- node.setAttribute(updateProp, newValue + '');
3935
- myfx.set(node, updateProp, newValue);
3936
- break;
3937
- default:
3938
- node.setAttribute(updateProp, newValue + '');
3939
- break;
3940
- }
3941
- }
3942
- return;
3943
- }
3944
- let path;
3945
- if (myfx.isString(modelProp)) {
3946
- path = myfx.toPath(modelProp)[0];
3947
- }
3948
- else {
3949
- path = myfx.last(varChain);
3950
- }
3951
- const rootPath = myfx.split(path, '.')[0];
3952
- if (!(rootPath in renderComponent) && !renderComponent._wrapperProp[rootPath]) {
3953
- showError(`model - property '${rootPath}' is not defined on the instance of ` + renderComponent.tagName);
3954
- }
3955
- let evList = renderComponent._eventList;
3956
- if (!myfx.isObject(modelValue) && !myfx.trim(modelValue))
3957
- modelValue = '';
3958
- if (node instanceof CompElem) {
3959
- node._initProps({ [updateProp]: modelValue });
3960
- let evName = 'update:' + updateProp;
3961
- evList.push([evName, function (e) {
3962
- console.debug('Model =>', path);
3963
- let ctx = this;
3964
- let pathFromWrapperComponent = ctx._wrapperProp[rootPath];
3965
- let hasPath = rootPath in ctx;
3966
- if (!hasPath && pathFromWrapperComponent && myfx.get(ctx.wrapperComponent, rootPath) === myfx.get(ctx, pathFromWrapperComponent)) {
3967
- ctx = ctx.wrapperComponent || ctx;
3968
- }
3969
- myfx.set(ctx, path, e.detail.value);
3970
- }, node]);
3971
- }
3972
- else if (node instanceof HTMLTextAreaElement) {
3973
- node.setAttribute(updateProp, modelValue + '');
3974
- let evName = 'input';
3975
- evList.push([evName, function (e) {
3976
- console.debug('Model =>', path);
3977
- let t = e.target;
3978
- myfx.set(this, path, t.value);
3979
- }, node]);
3980
- }
3981
- else if (node instanceof HTMLInputElement) {
3982
- let propName = '';
3983
- let evName = '';
3984
- switch (node.type) {
3985
- case 'checkbox':
3986
- case 'radio':
3987
- propName = 'checked';
3988
- evName = 'change';
3989
- break;
3990
- case 'text':
3991
- case 'email':
3992
- case 'number':
3993
- case 'password':
3994
- case 'search':
3995
- case 'tel':
3996
- case 'url':
3997
- propName = 'value';
3998
- evName = 'input';
3999
- break;
4000
- default:
4001
- propName = 'value';
4002
- evName = 'input';
4003
- break;
4004
- }
4005
- node.setAttribute(updateProp ?? propName, modelValue + '');
4006
- evList.push([evName, function (e) {
4007
- console.debug('Model =>', path);
4008
- let t = e.target;
4009
- myfx.set(this, path, t.value);
4010
- }, node]);
4011
- }
4012
- else if (node instanceof HTMLSelectElement) {
4013
- node.setAttribute(updateProp, modelValue + '');
4014
- evList.push(['change', function (e) {
4015
- console.debug('Model =>', path);
4016
- let t = e.target;
4017
- let ctx = this;
4018
- let pathFromWrapperComponent = ctx._wrapperProp[rootPath];
4019
- let hasPath = rootPath in ctx;
4020
- if (!hasPath && pathFromWrapperComponent && myfx.get(ctx.wrapperComponent, rootPath) === myfx.get(ctx, pathFromWrapperComponent)) {
4021
- ctx = ctx.wrapperComponent || ctx;
4022
- }
4023
- myfx.set(ctx, path, t.value);
4024
- }, node]);
4025
- }
4026
- };
4027
- }, [exports.EnterPointType.TAG]);
4028
-
4029
- const DisplayMap = new WeakMap();
4030
- /**
4031
- * display的快捷指令
4032
- * 如果
4033
- * @param isvisible 是否显示
4034
- * @param cbk 显示状态变更后调用的回调函数
4035
- */
4036
- const show = directive(function Show(isVisible, cbk) {
4037
- return (pointNode, [condi, cbk], oldArgs) => {
4038
- if (oldArgs && condi === oldArgs[0])
4039
- return;
4040
- let el = pointNode;
4041
- if (!DisplayMap.has(el)) {
4042
- let dis = el.style.display;
4043
- DisplayMap.set(el, dis == 'none' ? 'unset' : dis);
4044
- }
4045
- el.style.display = condi ? DisplayMap.get(el) : 'none';
4046
- if (cbk) {
4047
- cbk(el, condi);
4048
- }
4049
- };
4050
- }, [exports.EnterPointType.TAG]);
4051
-
4052
- /**
4053
- * 创建一个动态插槽内容
4054
- * @param cbk 回调函数,函数接收插槽上定义得变量
4055
- * @param slotName 插槽名词,默认default
4056
- */
4057
- const slot = directive(function Slot(cbk, slotName) {
4058
- return (pointNode, [cbk, slotName], oldArgs, { renderComponent, slotComponent }) => {
4059
- if (oldArgs)
4060
- return;
4061
- cbk = cbk.bind(renderComponent);
4062
- slotComponent._bindSlotHook(slotName || 'default', cbk);
4063
- };
4064
- }, [exports.EnterPointType.SLOT]);
4065
-
4066
- /**
4067
- * Css 辅助类
4068
- */
4069
- class CssHelper {
4070
- /**
4071
- * 用于转换style对象为标准style字符串,会自动转换对象key为短横线格式
4072
- * @param styles 样式对象
4073
- * @returns
4074
- */
4075
- static getCssText(styles, important = false) {
4076
- if (myfx.isString(styles))
4077
- return styles;
4078
- return myfx.join(myfx.map(styles, (v, k) => {
4079
- if (k.startsWith('--'))
4080
- return k + ":" + v + (important ? ' !important' : '');
4081
- return myfx.kebabCase(k) + ":" + v + (important ? ' !important' : '');
4082
- }), ';') + ';';
4083
- }
4084
- /**
4085
- * 设置样式
4086
- * @param styles 样式字符串或样式对象
4087
- * @param node HTML元素
4088
- * @returns 每个样式的旧值map
4089
- */
4090
- static setStyle(styles, node) {
4091
- if (myfx.isString(styles) && !myfx.trim(styles))
4092
- return;
4093
- let css = CssHelper.getCssText(styles);
4094
- node.style.cssText = css;
4095
- }
4096
- }
4097
-
4098
- /**
4099
- * 根据变量内容设置元素样式,仅能用于style属性
4100
- * @param styles 对象/字符串
4101
- */
4102
- const styles = directive(function Styles(...styles) {
4103
- return (pointNode, newArgs, oldArgs, { renderComponent }) => {
4104
- let el = pointNode;
4105
- let cssText = myfx.reduce(newArgs, (acc, v) => acc + CssHelper.getCssText(v), '');
4106
- let sKeys = myfx.compact(cssText.split(';').map(str => str.split(':')[0]));
4107
- let eKeys = myfx.compact(el.style.cssText.split(';'));
4108
- let ePairs = myfx.reject(eKeys, (str => sKeys.some(key => str.trim().startsWith(key))));
4109
- el.style.cssText = cssText + ePairs.join(';');
4110
- };
4111
- }, [exports.EnterPointType.STYLE]);
4112
-
4113
- /**
4114
- * 类似Model,实现属性的同步跟踪
4115
- * 设置组件prop,并监控 @update:prop 事件
4116
- * @param syncValue 双向绑定的组件变量
4117
- */
4118
- const sync = directive(function Sync(syncValue) {
4119
- return (pointNode, newArgs, oldArgs, { renderComponent, varChain, attrName }) => {
4120
- const targetComponent = pointNode;
4121
- if (oldArgs) {
4122
- if (!myfx.isEqual(newArgs, oldArgs)) {
4123
- targetComponent._updateProps({ [attrName]: newArgs[0] });
4124
- }
4125
- return;
4126
- }
4127
- let modelPath = myfx.last(varChain);
4128
- targetComponent._initProps({ [attrName]: newArgs[0] });
4129
- targetComponent.addEventListener('update:' + attrName, (e) => {
4130
- myfx.set(renderComponent, modelPath, e.detail.value);
4131
- });
4132
- };
4133
- }, [exports.EnterPointType.PROP]);
4134
-
4135
- /**
4136
- * 分支指令,具有switch / else if 两种模式
4137
- * @example
4138
- * switch 模式
4139
- * ${when(var, {
4140
- closed: () => html``, //case 1
4141
- connecting: () => html``, //case 2
4142
- default: () => html``// default是switch模式下的关键字key
4143
- })}
4144
-
4145
- else if 模式
4146
- * ${when(this.editingTitle, [
4147
- [(v: any) => v.substring(2) > 0, () => html`<div style="${PageHome.tunnelLight}"></div>`],
4148
- [(v: any) => v == 'closed', () => html`<div style="${PageHome.tunnelLight}"></div>`],
4149
- [() => true, () => html`默认`]
4150
- ])}
4151
- *
4152
- * @param condition 条件
4153
- * @param tmpl 模板
4154
- */
4155
- const when = directive(function When(value, cases) {
4156
- return (pointNode, [value, cases], oldArgs) => {
4157
- let defaultFn = () => html ``;
4158
- let conditionList = [];
4159
- let tmplList = [];
4160
- myfx.each(cases, (v, k) => {
4161
- if (myfx.isFunction(v)) {
4162
- conditionList.push(k);
4163
- tmplList.push(v);
4164
- }
4165
- else {
4166
- let condiFn = v[0];
4167
- let tmplFn = v[1];
4168
- conditionList.push(condiFn);
4169
- tmplList.push(tmplFn);
4170
- }
4171
- if (k === 'default') {
4172
- defaultFn = v;
4173
- }
4174
- });
4175
- let i = myfx.findIndex(conditionList, c => {
4176
- if (myfx.isFunction(c)) {
4177
- return c(value);
4178
- }
4179
- else {
4180
- return c == value;
4181
- }
4182
- });
4183
- if (oldArgs)
4184
- return [exports.DirectiveUpdateTag.REPLACE, myfx.call(tmplList[i] ?? defaultFn)];
4185
- return [exports.DirectiveUpdateTag.APPEND, myfx.call(tmplList[i] ?? defaultFn)];
4186
- };
4187
- }, [exports.EnterPointType.TEXT, exports.EnterPointType.SLOT]);
4188
-
4189
- exports.CompElem = CompElem;
4190
- exports.CssHelper = CssHelper;
4191
- exports.CssTemplate = CssTemplate;
4192
- exports.DI_COMMENT_START_NODE_MAP = DI_COMMENT_START_NODE_MAP;
4193
- exports.Decorator = Decorator;
4194
- exports.DecoratorWrapper = DecoratorWrapper;
4195
- exports.DomUtil = DomUtil;
4196
- exports.Template = Template;
4197
- exports.TextOrSlotDirectiveExecutorMap = TextOrSlotDirectiveExecutorMap;
4198
- exports.UpdatePoint = UpdatePoint;
4199
- exports._getObservedAttrs = _getObservedAttrs;
4200
- exports._getSuper = _getSuper;
4201
- exports._toUpdatePath = _toUpdatePath;
4202
- exports.bind = bind;
4203
- exports.buildHTML = buildHTML;
4204
- exports.classes = classes;
4205
- exports.computed = computed;
4206
- exports.createRef = createRef;
4207
- exports.css = css;
4208
- exports.debounced = debounced;
4209
- exports.decorator = decorator;
4210
- exports.decoratorWithNoArgs = decoratorWithNoArgs;
4211
- exports.directive = directive;
4212
- exports.event = event;
4213
- exports.forEach = forEach;
4214
- exports.getBooleanValue = getBooleanValue;
4215
- exports.getSlotComponent = getSlotComponent;
4216
- exports.html = html;
4217
- exports.htmlC = htmlC;
4218
- exports.htmlD = htmlD;
4219
- exports.ifElse = ifElse;
4220
- exports.ifTrue = ifTrue;
4221
- exports.isBooleanProp = isBooleanProp;
4222
- exports.makeState = makeState;
4223
- exports.model = model;
4224
- exports.onced = onced;
4225
- exports.prop = prop;
4226
- exports.query = query;
4227
- exports.queryAll = queryAll;
4228
- exports.show = show;
4229
- exports.showError = showError;
4230
- exports.showTagError = showTagError;
4231
- exports.showTagWarn = showTagWarn;
4232
- exports.showWarn = showWarn;
4233
- exports.slot = slot;
4234
- exports.state = state;
4235
- exports.styles = styles;
4236
- exports.sync = sync;
4237
- exports.tag = tag;
4238
- exports.throttled = throttled;
4239
- exports.updateDirective = updateDirective;
4240
- exports.watch = watch;
4241
- exports.when = when;
4242
-
4243
- Object.defineProperty(exports, '__esModule', { value: true });
4244
-
4245
- }));