compelem 0.20.0 → 0.20.2

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