@joker.front/core 1.2.170 → 1.2.237
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle.es.js +1 -3633
- package/dist/bundle.js +1 -3691
- package/package.json +6 -5
- package/types/component.d.ts +9 -3
- package/types/event-bus.d.ts +29 -4
- package/types/export.d.ts +11 -0
- package/types/index.d.ts +5 -4
- package/types/observer/dep.d.ts +0 -2
- package/types/observer/watcher.d.ts +2 -0
- package/types/parser/command/code.d.ts +1 -0
- package/types/parser/command/for.d.ts +1 -0
- package/types/parser/component.d.ts +0 -1
- package/types/parser/index.d.ts +2 -0
- package/types/parser/parser.d.ts +1 -0
- package/types/parser/render.d.ts +1 -0
- package/types/parser/vnode.d.ts +10 -7
- package/types/utils/index.d.ts +2 -2
package/dist/bundle.es.js
CHANGED
|
@@ -1,3633 +1 @@
|
|
|
1
|
-
import { EXPRESSHANDLERTAG, createFuntionBody, AST, RENDER_HANDLER, createComponent, createCommand } from '@joker.front/ast';
|
|
2
|
-
export { AST, RENDER_HANDLER, createCodeFunction, createCommand, createComment, createComponent, createElement, createFuntionBody, createText } from '@joker.front/ast';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 是否空函数
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* 是否是对象
|
|
9
|
-
*/
|
|
10
|
-
function isObject(object) {
|
|
11
|
-
return object !== null && typeof object === "object";
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* 获取对象自己本身的key/val
|
|
15
|
-
*/
|
|
16
|
-
function foEachProperties(obj, callBack) {
|
|
17
|
-
let ownKeys = Object.getOwnPropertyNames(obj);
|
|
18
|
-
ownKeys.forEach((key) => {
|
|
19
|
-
if (callBack(key, obj[key]) === false) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* 定义属性值
|
|
26
|
-
*/
|
|
27
|
-
function defineProperty(obj, key, val, enumerable) {
|
|
28
|
-
Object.defineProperty(obj, key, {
|
|
29
|
-
value: val,
|
|
30
|
-
enumerable: enumerable,
|
|
31
|
-
writable: true,
|
|
32
|
-
configurable: true
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* 判断是否有该属性(无论是否是原型链属性)
|
|
37
|
-
*/
|
|
38
|
-
function hasProperty(obj, key) {
|
|
39
|
-
if (key in obj) {
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* 对象自身属性中是否具有指定的属性,支持属性索引
|
|
46
|
-
*/
|
|
47
|
-
function hasOwnProperty(obj, key) {
|
|
48
|
-
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* 判断指定参数是否是一个纯粹的对象
|
|
52
|
-
*/
|
|
53
|
-
function isPlainObject(obj) {
|
|
54
|
-
return Object.prototype.toString.call(obj) === "[object Object]";
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* 克隆对象
|
|
58
|
-
* @param obj 目标对象
|
|
59
|
-
* @returns 新对象
|
|
60
|
-
*/
|
|
61
|
-
function deepClone(obj) {
|
|
62
|
-
// 创建一个新对象
|
|
63
|
-
let result;
|
|
64
|
-
if (Array.isArray(obj)) {
|
|
65
|
-
result = [];
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
result = {};
|
|
69
|
-
}
|
|
70
|
-
let keys = [...Object.keys(obj), ...Object.getOwnPropertySymbols(obj)];
|
|
71
|
-
for (let key of keys) {
|
|
72
|
-
let temp = obj[key];
|
|
73
|
-
// 如果字段的值也是一个对象则递归操作
|
|
74
|
-
if (typeof temp === "object") {
|
|
75
|
-
result[key] = deepClone(temp);
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
result[key] = temp;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
return result;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* 比较两个值是否相等
|
|
85
|
-
* @param val1
|
|
86
|
-
* @param val2
|
|
87
|
-
* @param shallow 浅检查,只做一级判断,默认为false,使用JsonStringfiy判断
|
|
88
|
-
*/
|
|
89
|
-
function isEqual(val1, val2, shallow) {
|
|
90
|
-
if (Array.isArray(val1) && Array.isArray(val2)) {
|
|
91
|
-
return _arrayEquals(val1, val2, shallow);
|
|
92
|
-
}
|
|
93
|
-
return _looseEqual(val1, val2, shallow);
|
|
94
|
-
}
|
|
95
|
-
function _looseEqual(val1, val2, shallow) {
|
|
96
|
-
let isObj1 = isObject(val1);
|
|
97
|
-
let isObj2 = isObject(val2);
|
|
98
|
-
if (isObj1 && isObj2) {
|
|
99
|
-
let keys = Object.keys(val1);
|
|
100
|
-
if (keys.length !== Object.keys(val2).length)
|
|
101
|
-
return false;
|
|
102
|
-
if (shallow) {
|
|
103
|
-
for (let key of keys) {
|
|
104
|
-
if (val1[key] !== val2[key])
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
return JSON.stringify(val1) === JSON.stringify(val2);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
else if (!isObj1 && !isObj2) {
|
|
114
|
-
return String(val1) === String(val2);
|
|
115
|
-
}
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* 去除数组中符合指定条件的第一个元素
|
|
121
|
-
*/
|
|
122
|
-
function remove(arr, item) {
|
|
123
|
-
let index = arr.indexOf(item);
|
|
124
|
-
if (index > -1) {
|
|
125
|
-
arr.splice(index, 1);
|
|
126
|
-
}
|
|
127
|
-
return arr;
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* 去除数组中符合指定条件的第一个元素
|
|
131
|
-
*/
|
|
132
|
-
function removeFilter(arr, filter) {
|
|
133
|
-
let index = arr.findIndex((item) => filter(item));
|
|
134
|
-
if (index > -1) {
|
|
135
|
-
arr.splice(index, 1);
|
|
136
|
-
}
|
|
137
|
-
return arr;
|
|
138
|
-
}
|
|
139
|
-
function _arrayEquals(val1, val2, shallow) {
|
|
140
|
-
if (val1.length !== val2.length) {
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
for (let i = 0; i < val1.length; i++) {
|
|
144
|
-
if (_looseEqual(val1[i], val2[i], shallow) === false) {
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return true;
|
|
149
|
-
}
|
|
150
|
-
/**
|
|
151
|
-
* 需要生成唯一标识符
|
|
152
|
-
* @param length 生成长度
|
|
153
|
-
* @returns
|
|
154
|
-
*/
|
|
155
|
-
function guid(length = 32) {
|
|
156
|
-
let result = [];
|
|
157
|
-
let keys = [
|
|
158
|
-
"0",
|
|
159
|
-
"1",
|
|
160
|
-
"2",
|
|
161
|
-
"3",
|
|
162
|
-
"4",
|
|
163
|
-
"5",
|
|
164
|
-
"6",
|
|
165
|
-
"7",
|
|
166
|
-
"8",
|
|
167
|
-
"9",
|
|
168
|
-
"a",
|
|
169
|
-
"b",
|
|
170
|
-
"c",
|
|
171
|
-
"d",
|
|
172
|
-
"e",
|
|
173
|
-
"f",
|
|
174
|
-
"g",
|
|
175
|
-
"h",
|
|
176
|
-
"i",
|
|
177
|
-
"j",
|
|
178
|
-
"k",
|
|
179
|
-
"l",
|
|
180
|
-
"m",
|
|
181
|
-
"n",
|
|
182
|
-
"o",
|
|
183
|
-
"p",
|
|
184
|
-
"q",
|
|
185
|
-
"r",
|
|
186
|
-
"s",
|
|
187
|
-
"t",
|
|
188
|
-
"u",
|
|
189
|
-
"v",
|
|
190
|
-
"w",
|
|
191
|
-
"x",
|
|
192
|
-
"y",
|
|
193
|
-
"z"
|
|
194
|
-
];
|
|
195
|
-
for (let i = 0; i < length; i++) {
|
|
196
|
-
let pos = Math.round(Math.random() * (keys.length - 1));
|
|
197
|
-
result.push(keys[pos]);
|
|
198
|
-
}
|
|
199
|
-
return result.join("");
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* 判断字符串是否为空
|
|
204
|
-
* @param val
|
|
205
|
-
* @returns
|
|
206
|
-
*/
|
|
207
|
-
function isEmptyStr(val) {
|
|
208
|
-
if (val) {
|
|
209
|
-
return val.trim() === "";
|
|
210
|
-
}
|
|
211
|
-
return true;
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* 转小写,可定制大写分隔符 分隔符默认'-'
|
|
215
|
-
* @param val 值
|
|
216
|
-
* @param splitKey 分隔符 默认'-'
|
|
217
|
-
* @returns
|
|
218
|
-
*/
|
|
219
|
-
function toLowerCase(val, splitKey = "-") {
|
|
220
|
-
val = val || "";
|
|
221
|
-
let valSplit = val.split(/(?=[A-Z])/);
|
|
222
|
-
return valSplit.map((m) => m.toLowerCase()).join(splitKey);
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
let noop = (...args) => { };
|
|
226
|
-
|
|
227
|
-
let leve = "warn";
|
|
228
|
-
const loggerLeveWeight = ["silent", "error", "warn", "info"];
|
|
229
|
-
//时间戳
|
|
230
|
-
function getTimer() {
|
|
231
|
-
let date = new Date();
|
|
232
|
-
function supplyZero(value, length = 2) {
|
|
233
|
-
return value.toString().padStart(length, "0");
|
|
234
|
-
}
|
|
235
|
-
return (supplyZero(date.getHours()) +
|
|
236
|
-
":" +
|
|
237
|
-
supplyZero(date.getMinutes()) +
|
|
238
|
-
":" +
|
|
239
|
-
supplyZero(date.getSeconds()) +
|
|
240
|
-
":" +
|
|
241
|
-
supplyZero(date.getMilliseconds(), 3));
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* 日志输出
|
|
245
|
-
*
|
|
246
|
-
* 当前方法只控制日志输出等级,不做逻辑注入
|
|
247
|
-
* 无论是H5、小程序、客户端,都需要在浏览器/V8中执行
|
|
248
|
-
* 日志输出到容器内即可
|
|
249
|
-
* @param type
|
|
250
|
-
* @param tagName
|
|
251
|
-
* @param content
|
|
252
|
-
* @param data 扩展数据
|
|
253
|
-
*/
|
|
254
|
-
function writeLog(type, tagName, content, data) {
|
|
255
|
-
if (loggerLeveWeight.indexOf(type) <= loggerLeveWeight.indexOf(leve)) {
|
|
256
|
-
if (data === undefined) {
|
|
257
|
-
console[type](`${getTimer()} [${tagName}]:`, content);
|
|
258
|
-
}
|
|
259
|
-
else {
|
|
260
|
-
console[type](`${getTimer()} [${tagName}]:`, content, data);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* 信息
|
|
266
|
-
* @param tag
|
|
267
|
-
* @param content
|
|
268
|
-
*/
|
|
269
|
-
function info(tag, content, data) {
|
|
270
|
-
writeLog("info", tag, content, data);
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* 警告
|
|
274
|
-
* @param tag
|
|
275
|
-
* @param content
|
|
276
|
-
*/
|
|
277
|
-
function warn(tag, content, data) {
|
|
278
|
-
writeLog("warn", tag, content, data);
|
|
279
|
-
}
|
|
280
|
-
/**
|
|
281
|
-
* 错误
|
|
282
|
-
* @param tag
|
|
283
|
-
* @param content
|
|
284
|
-
*/
|
|
285
|
-
function error(tag, content, data) {
|
|
286
|
-
writeLog("error", tag, content, data);
|
|
287
|
-
}
|
|
288
|
-
function setLoggerLeve(_leve) {
|
|
289
|
-
leve = _leve;
|
|
290
|
-
}
|
|
291
|
-
let logger = {
|
|
292
|
-
info,
|
|
293
|
-
warn,
|
|
294
|
-
error,
|
|
295
|
-
setLoggerLeve
|
|
296
|
-
};
|
|
297
|
-
const escape2HtmlData = {
|
|
298
|
-
lt: "<",
|
|
299
|
-
gt: ">",
|
|
300
|
-
nbsp: " ",
|
|
301
|
-
amp: "&",
|
|
302
|
-
quot: '"',
|
|
303
|
-
"#39": "'"
|
|
304
|
-
};
|
|
305
|
-
/**
|
|
306
|
-
* escape => html
|
|
307
|
-
* @param str
|
|
308
|
-
* @returns
|
|
309
|
-
*/
|
|
310
|
-
function escape2Html(str) {
|
|
311
|
-
return str.replace(/&(lt|gt|nbsp|amp|quot|#39);/gi, (all, t) => {
|
|
312
|
-
return escape2HtmlData[t] || "";
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
let otherWindowDeps = [];
|
|
317
|
-
function registerOtherWindowDep(dep) {
|
|
318
|
-
otherWindowDeps.push(dep);
|
|
319
|
-
}
|
|
320
|
-
function removeOtherWindowDep(dep) {
|
|
321
|
-
remove(otherWindowDeps, dep);
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* 作为观察者和对象代理中间的关系桥
|
|
325
|
-
* 数据变更时:Ob->dep->watcher
|
|
326
|
-
* 设置依赖时:watcher->dep
|
|
327
|
-
*/
|
|
328
|
-
class Dep {
|
|
329
|
-
/**
|
|
330
|
-
* 关系id,仅在production模式下生效
|
|
331
|
-
*/
|
|
332
|
-
id = process.env.NODE_ENV === "production" ? "" : guid();
|
|
333
|
-
/**
|
|
334
|
-
* 当前目标的监听者
|
|
335
|
-
*
|
|
336
|
-
* 在更改值之前,设置该静态值,使其在值变更时收集相应的依赖关系
|
|
337
|
-
* 设置完毕后清除该值
|
|
338
|
-
*
|
|
339
|
-
* 之所以采用静态值,不采用方法的原因:
|
|
340
|
-
* 可能存在多值变更,或者读取
|
|
341
|
-
*/
|
|
342
|
-
static target;
|
|
343
|
-
watchers = new Map();
|
|
344
|
-
/**
|
|
345
|
-
* 设置依赖
|
|
346
|
-
* @param key
|
|
347
|
-
*/
|
|
348
|
-
depend(key) {
|
|
349
|
-
Dep.target?.addDep(this, key);
|
|
350
|
-
otherWindowDeps.forEach((n) => {
|
|
351
|
-
n.target?.addDep(this, key);
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
/**
|
|
355
|
-
* 添加观察者
|
|
356
|
-
* @param key
|
|
357
|
-
* @param watcher
|
|
358
|
-
*/
|
|
359
|
-
addWatcher(key, watcher) {
|
|
360
|
-
let watchers = this.watchers.get(key) || [];
|
|
361
|
-
watchers.push(watcher);
|
|
362
|
-
this.watchers.set(key, watchers);
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* 删除观察者
|
|
366
|
-
* @param key
|
|
367
|
-
* @param watcher
|
|
368
|
-
*/
|
|
369
|
-
removeWatcher(key, watcher) {
|
|
370
|
-
let watchers = this.watchers.get(key);
|
|
371
|
-
if (watchers) {
|
|
372
|
-
remove(watchers, watcher);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
/**
|
|
376
|
-
* 通知key下面的观察者
|
|
377
|
-
* @param key
|
|
378
|
-
*/
|
|
379
|
-
notify(key) {
|
|
380
|
-
let watchers = this.watchers.get(key);
|
|
381
|
-
if (watchers) {
|
|
382
|
-
//移除已经销毁的数据
|
|
383
|
-
removeFilter(watchers, (w) => {
|
|
384
|
-
return w.isDestroy;
|
|
385
|
-
});
|
|
386
|
-
/**
|
|
387
|
-
* 由于watchers 是个动态实时变化的
|
|
388
|
-
* 所以通知时,只广播当前的观察者列队
|
|
389
|
-
* 动态新增删除的不做处理
|
|
390
|
-
*/
|
|
391
|
-
[...watchers].forEach((w) => {
|
|
392
|
-
w.isDestroy === false && w.update();
|
|
393
|
-
});
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
function notifyGroupDeps(list) {
|
|
398
|
-
let watchers = [];
|
|
399
|
-
let hasNotifyWatchers = [];
|
|
400
|
-
//这里将队列重新排列,防止过程中新增监听造成不必要的循环广播
|
|
401
|
-
list.forEach((keys, dep) => {
|
|
402
|
-
keys.forEach((key) => {
|
|
403
|
-
watchers.push(...(dep.watchers.get(key) || []));
|
|
404
|
-
});
|
|
405
|
-
});
|
|
406
|
-
watchers.forEach((n) => {
|
|
407
|
-
if (hasNotifyWatchers.includes(n))
|
|
408
|
-
return;
|
|
409
|
-
n.isDestroy === false && n.update();
|
|
410
|
-
hasNotifyWatchers.push(n);
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
/**
|
|
415
|
-
* 存放劫持对象的Dep的Key
|
|
416
|
-
*/
|
|
417
|
-
const OBJECTPROXY_DEPID = Symbol.for("__JOKER_OBJECT_PROXY_DEP_ID__");
|
|
418
|
-
const OBJECTPROXY_DATA_KEY = Symbol.for("__JOKER_OBJECT_PROXY_DATA_KEY__");
|
|
419
|
-
/**
|
|
420
|
-
* 针对深度劫持关系时,需要给该对象做一个虚拟劫持的关系Key,方便事件传播
|
|
421
|
-
*/
|
|
422
|
-
const OBJECTPROXY_DEPLEVE_ID = Symbol.for("__JOKER_OBJECTPROXY_DEPLEVE_ID__");
|
|
423
|
-
/**
|
|
424
|
-
* 检测是否允许劫持代理
|
|
425
|
-
* @param data
|
|
426
|
-
* @returns
|
|
427
|
-
*/
|
|
428
|
-
function checkEnableProxy(data) {
|
|
429
|
-
return (isObject(data) &&
|
|
430
|
-
(Array.isArray(data) || isPlainObject(data)) &&
|
|
431
|
-
//可扩展
|
|
432
|
-
Object.isExtensible(data) &&
|
|
433
|
-
//非冻结
|
|
434
|
-
!Object.isFrozen(data) &&
|
|
435
|
-
!(data instanceof Element) &&
|
|
436
|
-
!(JOKER_VNODE_TAG in data) &&
|
|
437
|
-
!(JOKER_SHALLOW_OBSERVER_TAG in data) &&
|
|
438
|
-
!(JOKER_COMPONENT_TAG in data));
|
|
439
|
-
}
|
|
440
|
-
function proxyData(data) {
|
|
441
|
-
let proxyDepTarget = getProxyDep(data);
|
|
442
|
-
//如果当前数据已经被数据劫持,则直接返回,防止重复劫持监听
|
|
443
|
-
if (proxyDepTarget) {
|
|
444
|
-
return data;
|
|
445
|
-
}
|
|
446
|
-
let readiedData = Reflect.get(data, OBJECTPROXY_DATA_KEY);
|
|
447
|
-
if (readiedData) {
|
|
448
|
-
return readiedData;
|
|
449
|
-
}
|
|
450
|
-
let dep = new Dep();
|
|
451
|
-
//首次重置值
|
|
452
|
-
let resetData = true;
|
|
453
|
-
let result = new Proxy(data, {
|
|
454
|
-
get(target, key, receiver) {
|
|
455
|
-
// 该属性是为了解决非proxy下的数据重复依赖劫持问题
|
|
456
|
-
// 如果直接获取proxy中的该属性,可能是全属性遍历,这时返回undefined即可
|
|
457
|
-
//@ts-ignore
|
|
458
|
-
if (key === OBJECTPROXY_DATA_KEY) {
|
|
459
|
-
return undefined;
|
|
460
|
-
}
|
|
461
|
-
if (key === OBJECTPROXY_DEPID) {
|
|
462
|
-
return dep;
|
|
463
|
-
}
|
|
464
|
-
//空索引
|
|
465
|
-
if (key === OBJECTPROXY_DEPLEVE_ID) {
|
|
466
|
-
return undefined;
|
|
467
|
-
}
|
|
468
|
-
let result = Reflect.get(target, key);
|
|
469
|
-
if (hasProperty(target, key) === false && key !== "length") {
|
|
470
|
-
return result;
|
|
471
|
-
}
|
|
472
|
-
dep.depend(key);
|
|
473
|
-
if (checkEnableProxy(result)) {
|
|
474
|
-
//如果是可劫持对象,并且存在Dep关系,则做深度为1的空key关系
|
|
475
|
-
//如果不是,并且没有被劫持,理论上不存在,可能由Object原型方法添加,不做考虑
|
|
476
|
-
getProxyDep(result)?.depend(OBJECTPROXY_DEPLEVE_ID);
|
|
477
|
-
}
|
|
478
|
-
return result;
|
|
479
|
-
},
|
|
480
|
-
set(target, key, value) {
|
|
481
|
-
if (resetData) {
|
|
482
|
-
Reflect.set(target, key, value);
|
|
483
|
-
return true;
|
|
484
|
-
}
|
|
485
|
-
if (checkEnableProxy(value)) {
|
|
486
|
-
//如果是对象,则对其进行数据依赖采集
|
|
487
|
-
value = observer(value);
|
|
488
|
-
}
|
|
489
|
-
let isNewProperty = hasOwnProperty(target, key) === false;
|
|
490
|
-
Reflect.set(target, key, value);
|
|
491
|
-
notifyDep(dep, key);
|
|
492
|
-
//数组长度变更,属于数组change,则对该对象做change广播
|
|
493
|
-
if (Array.isArray(target)) {
|
|
494
|
-
key === "length" && notifyDep(dep, OBJECTPROXY_DEPLEVE_ID);
|
|
495
|
-
}
|
|
496
|
-
else if (isNewProperty) {
|
|
497
|
-
//Object 类型,监听新属性增加
|
|
498
|
-
notifyDep(dep, OBJECTPROXY_DEPLEVE_ID);
|
|
499
|
-
}
|
|
500
|
-
return true;
|
|
501
|
-
},
|
|
502
|
-
deleteProperty(target, key) {
|
|
503
|
-
Reflect.deleteProperty(target, key);
|
|
504
|
-
//操作成功 && 非数组,删除属性时,要进行广播
|
|
505
|
-
if (Array.isArray(target) === false) {
|
|
506
|
-
notifyDep(dep, OBJECTPROXY_DEPLEVE_ID);
|
|
507
|
-
}
|
|
508
|
-
return true;
|
|
509
|
-
}
|
|
510
|
-
});
|
|
511
|
-
//新增临时挂载,已解决循环数据引用一致性问题
|
|
512
|
-
defineProperty(data, OBJECTPROXY_DATA_KEY, result, false);
|
|
513
|
-
//对所有可被劫持的属性进行深度遍历劫持
|
|
514
|
-
for (let key in data) {
|
|
515
|
-
let itemData = data[key];
|
|
516
|
-
//可被代理 && 没有代理
|
|
517
|
-
if (checkEnableProxy(itemData) && !getProxyDep(itemData)) {
|
|
518
|
-
//@ts-ignore
|
|
519
|
-
result[key] = proxyData(data[key]);
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
resetData = false;
|
|
523
|
-
return result;
|
|
524
|
-
}
|
|
525
|
-
/**
|
|
526
|
-
* 获取劫持对象的Dep
|
|
527
|
-
* @param data
|
|
528
|
-
* @returns
|
|
529
|
-
*/
|
|
530
|
-
function getProxyDep(data) {
|
|
531
|
-
//@ts-ignore
|
|
532
|
-
if (isObject(data)) {
|
|
533
|
-
let dep = Reflect.get(data, OBJECTPROXY_DEPID);
|
|
534
|
-
if (dep) {
|
|
535
|
-
//@ts-ignore
|
|
536
|
-
return dep;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
/**
|
|
541
|
-
* 数据劫持
|
|
542
|
-
* @param data 数据
|
|
543
|
-
* @param clone 是否clone
|
|
544
|
-
* @returns 返回可观察对象
|
|
545
|
-
*/
|
|
546
|
-
function observer(data, clone = false) {
|
|
547
|
-
if (checkEnableProxy(data) === false) {
|
|
548
|
-
throw new Error("当前传入的数据不是正确的数据类型,必须是数组或者对象");
|
|
549
|
-
}
|
|
550
|
-
if (clone) {
|
|
551
|
-
return proxyData(deepClone(data));
|
|
552
|
-
}
|
|
553
|
-
else {
|
|
554
|
-
return proxyData(data);
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
/**
|
|
558
|
-
* 定义可劫持观察的属性
|
|
559
|
-
*
|
|
560
|
-
* 该方法会污染value深层,如想纯净数据,自行clone
|
|
561
|
-
* @param target
|
|
562
|
-
* @param key
|
|
563
|
-
* @param value
|
|
564
|
-
*/
|
|
565
|
-
function defineObserverProperty(target, key, value) {
|
|
566
|
-
let propertyVal = value;
|
|
567
|
-
if (checkEnableProxy(value)) {
|
|
568
|
-
//如果是对象,则对其进行数据依赖采集
|
|
569
|
-
propertyVal = observer(value);
|
|
570
|
-
}
|
|
571
|
-
let dep = new Dep();
|
|
572
|
-
Object.defineProperty(target, key, {
|
|
573
|
-
//可枚举
|
|
574
|
-
enumerable: true,
|
|
575
|
-
//不可再定义
|
|
576
|
-
configurable: true,
|
|
577
|
-
get: () => {
|
|
578
|
-
dep.depend(key);
|
|
579
|
-
if (checkEnableProxy(propertyVal)) {
|
|
580
|
-
//如果是可劫持对象,并且存在Dep关系,则做深度为1的空key关系
|
|
581
|
-
getProxyDep(propertyVal)?.depend(OBJECTPROXY_DEPLEVE_ID);
|
|
582
|
-
}
|
|
583
|
-
return propertyVal;
|
|
584
|
-
},
|
|
585
|
-
set: (value) => {
|
|
586
|
-
if (value === propertyVal) {
|
|
587
|
-
return;
|
|
588
|
-
}
|
|
589
|
-
if (checkEnableProxy(value)) {
|
|
590
|
-
//如果是对象,则对其进行数据依赖采集
|
|
591
|
-
value = observer(value);
|
|
592
|
-
//不做深层通知
|
|
593
|
-
}
|
|
594
|
-
propertyVal = value;
|
|
595
|
-
notifyDep(dep, key);
|
|
596
|
-
}
|
|
597
|
-
});
|
|
598
|
-
}
|
|
599
|
-
const JOKER_SHALLOW_OBSERVER_TAG = Symbol.for("JOKER_SHALLOW_OBSERVER");
|
|
600
|
-
/**
|
|
601
|
-
* 浅劫持监听,不污染数据源,只对根值监听,不对属性监听
|
|
602
|
-
* @returns
|
|
603
|
-
*/
|
|
604
|
-
class ShallowObserver {
|
|
605
|
-
data;
|
|
606
|
-
[JOKER_SHALLOW_OBSERVER_TAG] = true;
|
|
607
|
-
dep = new Dep();
|
|
608
|
-
constructor(data) {
|
|
609
|
-
this.data = data;
|
|
610
|
-
}
|
|
611
|
-
/**
|
|
612
|
-
* 是否有变更
|
|
613
|
-
*/
|
|
614
|
-
isChanged = false;
|
|
615
|
-
get value() {
|
|
616
|
-
this.dep.depend(OBJECTPROXY_DEPLEVE_ID);
|
|
617
|
-
return this.data;
|
|
618
|
-
}
|
|
619
|
-
set value(newVal) {
|
|
620
|
-
if (Object.is(newVal, this.data) === false) {
|
|
621
|
-
this.isChanged = true;
|
|
622
|
-
this.data = newVal;
|
|
623
|
-
notifyDep(this.dep, OBJECTPROXY_DEPLEVE_ID);
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
/**
|
|
628
|
-
* 用于标记是否是组合回复
|
|
629
|
-
*/
|
|
630
|
-
let isCombined = false;
|
|
631
|
-
/**
|
|
632
|
-
* 组合回复采集队列
|
|
633
|
-
*/
|
|
634
|
-
let combinedReplyQueue = new Map();
|
|
635
|
-
/**
|
|
636
|
-
* 通知dep,通过isCombined执行不同的流程
|
|
637
|
-
*/
|
|
638
|
-
function notifyDep(dep, key) {
|
|
639
|
-
//非合并回复直接回复
|
|
640
|
-
if (isCombined === false)
|
|
641
|
-
dep.notify(key);
|
|
642
|
-
//合并回复,做去重收集
|
|
643
|
-
else {
|
|
644
|
-
let depQueue = combinedReplyQueue.get(dep);
|
|
645
|
-
if (depQueue === undefined) {
|
|
646
|
-
depQueue = [];
|
|
647
|
-
combinedReplyQueue.set(dep, depQueue);
|
|
648
|
-
}
|
|
649
|
-
if (depQueue.includes(key) === false) {
|
|
650
|
-
depQueue.push(key);
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
/**
|
|
655
|
-
* 组合回复,针对大量值变更,又不想频繁更新DOM,
|
|
656
|
-
* 可通过该方法实现一个作用域内的统一组合回复
|
|
657
|
-
* @param func 处理方法
|
|
658
|
-
* @returns
|
|
659
|
-
*/
|
|
660
|
-
function combinedReply(func) {
|
|
661
|
-
isCombined = true;
|
|
662
|
-
try {
|
|
663
|
-
func();
|
|
664
|
-
}
|
|
665
|
-
catch (e) {
|
|
666
|
-
isCombined = false;
|
|
667
|
-
combinedReplyQueue.clear();
|
|
668
|
-
logger.error("数据劫持", "数据劫持组合回复在做变更采集时,遇到了阻塞错误,不做响应,请检查", e);
|
|
669
|
-
return;
|
|
670
|
-
}
|
|
671
|
-
isCombined = false;
|
|
672
|
-
//组合回复
|
|
673
|
-
notifyGroupDeps(combinedReplyQueue);
|
|
674
|
-
combinedReplyQueue.clear();
|
|
675
|
-
}
|
|
676
|
-
/**
|
|
677
|
-
* 判断一个值是否是已被数据代理劫持
|
|
678
|
-
*/
|
|
679
|
-
function isObserverData(data) {
|
|
680
|
-
return getProxyDep(data) !== undefined;
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
const LOGTAG$5 = "数据观察";
|
|
684
|
-
/**
|
|
685
|
-
* 将取值表达式转换为get方法
|
|
686
|
-
* @param exp
|
|
687
|
-
* @returns
|
|
688
|
-
*/
|
|
689
|
-
function transformGetter(exp) {
|
|
690
|
-
//过滤非正常属性
|
|
691
|
-
if (/[^\w.$]/.test(exp)) {
|
|
692
|
-
return;
|
|
693
|
-
}
|
|
694
|
-
let exps = exp.split(".");
|
|
695
|
-
return function (data) {
|
|
696
|
-
let result = data;
|
|
697
|
-
exps.forEach((key) => {
|
|
698
|
-
if (!result) {
|
|
699
|
-
return;
|
|
700
|
-
}
|
|
701
|
-
result = result[key];
|
|
702
|
-
});
|
|
703
|
-
return result;
|
|
704
|
-
};
|
|
705
|
-
}
|
|
706
|
-
/**
|
|
707
|
-
* 观察者
|
|
708
|
-
*
|
|
709
|
-
* 负责观察对象,并收集依赖关系,并在值变更时做出回调响应
|
|
710
|
-
*/
|
|
711
|
-
class Watcher {
|
|
712
|
-
ob;
|
|
713
|
-
updateCallBack;
|
|
714
|
-
forceCallBack;
|
|
715
|
-
getter;
|
|
716
|
-
value;
|
|
717
|
-
isDestroy = false;
|
|
718
|
-
/**
|
|
719
|
-
* 运行时的关系收集
|
|
720
|
-
*
|
|
721
|
-
* 主要作用是:运行时做基本的重复过滤,并收集当前“有效的”Dep关系
|
|
722
|
-
* 一个Dep 肯定对应一个对象, 对象的key不会出现重复
|
|
723
|
-
*/
|
|
724
|
-
runRelations = new Map();
|
|
725
|
-
/**
|
|
726
|
-
* 实际关系
|
|
727
|
-
*/
|
|
728
|
-
relations = new Map();
|
|
729
|
-
/**
|
|
730
|
-
*
|
|
731
|
-
* @param ob 数据源
|
|
732
|
-
* @param expOrFn 表达式(string|Function)
|
|
733
|
-
* @param updateCallBack update回调
|
|
734
|
-
* @param forceCallBack 是否强制回调, 有些值未变更时也会强制回调
|
|
735
|
-
*/
|
|
736
|
-
constructor(ob, updateCallBack, expOrFn, forceCallBack) {
|
|
737
|
-
this.ob = ob;
|
|
738
|
-
this.updateCallBack = updateCallBack;
|
|
739
|
-
this.forceCallBack = forceCallBack;
|
|
740
|
-
if (ob === undefined) {
|
|
741
|
-
throw new Error("无法对underfind进行变更观察");
|
|
742
|
-
}
|
|
743
|
-
if (expOrFn === undefined) {
|
|
744
|
-
this.getter = (obj) => obj;
|
|
745
|
-
}
|
|
746
|
-
else if (typeof expOrFn === "function") {
|
|
747
|
-
this.getter = expOrFn;
|
|
748
|
-
}
|
|
749
|
-
else {
|
|
750
|
-
let getFunc = transformGetter(expOrFn);
|
|
751
|
-
if (getFunc === undefined) {
|
|
752
|
-
throw new Error(expOrFn + "解析失败,无法明确读取表达式,请检查expOrFn参数,或采用function模式");
|
|
753
|
-
}
|
|
754
|
-
this.getter = getFunc;
|
|
755
|
-
}
|
|
756
|
-
if (this.getter === undefined) {
|
|
757
|
-
logger.error(LOGTAG$5, "getter创建失败", arguments);
|
|
758
|
-
}
|
|
759
|
-
this.value = this.getValue();
|
|
760
|
-
}
|
|
761
|
-
getValue() {
|
|
762
|
-
//当前watcher被销毁,可能存在从下向上的监听广播,这里不做处理
|
|
763
|
-
if (this.getter === undefined) {
|
|
764
|
-
return;
|
|
765
|
-
}
|
|
766
|
-
Dep.target = this;
|
|
767
|
-
let targetData = typeof this.ob === "function" ? this.ob() : this.ob;
|
|
768
|
-
let value;
|
|
769
|
-
try {
|
|
770
|
-
value = this.getter.call(targetData, targetData);
|
|
771
|
-
}
|
|
772
|
-
catch (e) {
|
|
773
|
-
logger.error(LOGTAG$5, `获取值失败,执行方法:${this.getter.toString()}`);
|
|
774
|
-
throw e;
|
|
775
|
-
}
|
|
776
|
-
Dep.target = undefined;
|
|
777
|
-
this.clearnDeps();
|
|
778
|
-
return value;
|
|
779
|
-
}
|
|
780
|
-
/**
|
|
781
|
-
* 添加Dep关系
|
|
782
|
-
* @param dep
|
|
783
|
-
* @param key
|
|
784
|
-
*/
|
|
785
|
-
addDep(dep, key) {
|
|
786
|
-
let runItem = this.runRelations.get(dep);
|
|
787
|
-
if (runItem === undefined || runItem.includes(key) === false) {
|
|
788
|
-
runItem = runItem || [];
|
|
789
|
-
runItem.push(key);
|
|
790
|
-
this.runRelations.set(dep, runItem);
|
|
791
|
-
let depItem = this.relations.get(dep);
|
|
792
|
-
//判断之前有没有该关系的存储,如果没有则添加
|
|
793
|
-
//在最终clean时,会重新runRelations-》relations的转换
|
|
794
|
-
if (depItem === undefined || depItem.includes(key) === false) {
|
|
795
|
-
dep.addWatcher(key, this);
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
/**
|
|
800
|
-
* 更新值,并对其进行响应
|
|
801
|
-
*/
|
|
802
|
-
update() {
|
|
803
|
-
let newVal = this.getValue();
|
|
804
|
-
let oldVal = this.value;
|
|
805
|
-
//强制回调||值变更||值时个对象(对象时引用类型无法查看是否变更)
|
|
806
|
-
if (this.forceCallBack || newVal !== oldVal || isObject(newVal)) {
|
|
807
|
-
this.value = newVal;
|
|
808
|
-
//这里过滤一些引用不想等,但值相等的值,只是不做响应,但不影响下次的值变更
|
|
809
|
-
//这里没有过滤掉this.value = newVal;
|
|
810
|
-
if (newVal !== oldVal && !this.forceCallBack && isEqual(newVal, oldVal, true)) {
|
|
811
|
-
return;
|
|
812
|
-
}
|
|
813
|
-
this.updateCallBack(newVal, oldVal);
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
destroy() {
|
|
817
|
-
this.relations.forEach((keys, dep) => {
|
|
818
|
-
for (let key of keys) {
|
|
819
|
-
dep.removeWatcher(key, this);
|
|
820
|
-
}
|
|
821
|
-
});
|
|
822
|
-
this.isDestroy = true;
|
|
823
|
-
this.relations.clear();
|
|
824
|
-
this.runRelations.clear();
|
|
825
|
-
this.ob = undefined;
|
|
826
|
-
this.value = undefined;
|
|
827
|
-
this.getter = undefined;
|
|
828
|
-
}
|
|
829
|
-
clearnDeps() {
|
|
830
|
-
this.relations.forEach((keys, dep) => {
|
|
831
|
-
let runItem = this.runRelations.get(dep);
|
|
832
|
-
for (let key of keys) {
|
|
833
|
-
if (runItem) {
|
|
834
|
-
if (runItem.includes(key) === false) {
|
|
835
|
-
dep.removeWatcher(key, this);
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
else {
|
|
839
|
-
//移除所有的dep属性关系
|
|
840
|
-
//不移除dep,因为对象属性还在
|
|
841
|
-
dep.removeWatcher(key, this);
|
|
842
|
-
}
|
|
843
|
-
}
|
|
844
|
-
});
|
|
845
|
-
this.relations.clear();
|
|
846
|
-
this.relations = this.runRelations;
|
|
847
|
-
this.runRelations = new Map();
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
/**
|
|
852
|
-
* IOC依赖注入容器
|
|
853
|
-
*
|
|
854
|
-
* IOC依赖注入适用场景:
|
|
855
|
-
* 内部已规划的API、Interface,需要在外部对其进行逻辑注入的场景
|
|
856
|
-
* 区分于plugin,plugin是根据整体声明周期做的切面注入
|
|
857
|
-
*/
|
|
858
|
-
var IContainer;
|
|
859
|
-
(function (IContainer) {
|
|
860
|
-
let binds = new Map();
|
|
861
|
-
function bind(tagId) {
|
|
862
|
-
return {
|
|
863
|
-
to: (target) => {
|
|
864
|
-
if (binds.has(tagId)) {
|
|
865
|
-
throw new Error(`TagId:${tagId.toString()}已注入实现类,请勿重复注入。`);
|
|
866
|
-
}
|
|
867
|
-
binds.set(tagId, target);
|
|
868
|
-
}
|
|
869
|
-
};
|
|
870
|
-
}
|
|
871
|
-
IContainer.bind = bind;
|
|
872
|
-
function get(tagId, ...params) {
|
|
873
|
-
let target = binds.get(tagId);
|
|
874
|
-
if (target) {
|
|
875
|
-
return new target(...params);
|
|
876
|
-
}
|
|
877
|
-
return;
|
|
878
|
-
}
|
|
879
|
-
IContainer.get = get;
|
|
880
|
-
})(IContainer || (IContainer = {}));
|
|
881
|
-
|
|
882
|
-
const JOKER_VNODE_TAG = Symbol.for("JOKER_VNODE_TAG");
|
|
883
|
-
/**
|
|
884
|
-
* 虚拟DOM
|
|
885
|
-
*
|
|
886
|
-
* 该控件分类区别于AST,分类是按照实际输出类型作为划分
|
|
887
|
-
*/
|
|
888
|
-
var VNode;
|
|
889
|
-
(function (VNode) {
|
|
890
|
-
VNode.PARSERKEY = Symbol.for("JOKER_PARSER_KEY");
|
|
891
|
-
/**
|
|
892
|
-
* VNode 基类
|
|
893
|
-
*/
|
|
894
|
-
class Node {
|
|
895
|
-
parent;
|
|
896
|
-
[JOKER_VNODE_TAG] = true;
|
|
897
|
-
/**
|
|
898
|
-
* 是否是静态节点,非动态节点。例如:element、text、comment等
|
|
899
|
-
*/
|
|
900
|
-
static;
|
|
901
|
-
output;
|
|
902
|
-
[VNode.PARSERKEY];
|
|
903
|
-
childrens;
|
|
904
|
-
/**
|
|
905
|
-
* 当前节点是否睡眠
|
|
906
|
-
*/
|
|
907
|
-
sleep = false;
|
|
908
|
-
constructor(parent) {
|
|
909
|
-
this.parent = parent;
|
|
910
|
-
}
|
|
911
|
-
/**
|
|
912
|
-
* 上一个节点
|
|
913
|
-
*/
|
|
914
|
-
get prev() {
|
|
915
|
-
if (this.parent) {
|
|
916
|
-
return this.parent.childrens?.[this.parent.childrens?.indexOf(this) - 1];
|
|
917
|
-
}
|
|
918
|
-
return;
|
|
919
|
-
}
|
|
920
|
-
/**
|
|
921
|
-
* 下一个节点
|
|
922
|
-
*/
|
|
923
|
-
get next() {
|
|
924
|
-
if (this.parent) {
|
|
925
|
-
return this.parent.childrens?.[this.parent.childrens?.indexOf(this) + 1];
|
|
926
|
-
}
|
|
927
|
-
return;
|
|
928
|
-
}
|
|
929
|
-
/**
|
|
930
|
-
* 匹配第一个符合要求的祖先元素
|
|
931
|
-
* @param match
|
|
932
|
-
* @param breakWhenVRoot 是否过滤到当前视图根时中断
|
|
933
|
-
* @returns
|
|
934
|
-
*/
|
|
935
|
-
closest(filter, breakWhenVRoot) {
|
|
936
|
-
if (filter(this) === true) {
|
|
937
|
-
return this;
|
|
938
|
-
}
|
|
939
|
-
let parent = this.parent;
|
|
940
|
-
while (parent) {
|
|
941
|
-
if (breakWhenVRoot && parent instanceof VNode.Root)
|
|
942
|
-
return;
|
|
943
|
-
if (filter(parent) === true) {
|
|
944
|
-
return parent;
|
|
945
|
-
}
|
|
946
|
-
parent = parent.parent;
|
|
947
|
-
}
|
|
948
|
-
return;
|
|
949
|
-
}
|
|
950
|
-
/**
|
|
951
|
-
* 返回所有匹配的子元素
|
|
952
|
-
* @param filter 返回true则记录,返回false则跳过该元素的子集
|
|
953
|
-
* @returns
|
|
954
|
-
*/
|
|
955
|
-
find(filter, childrens, _out) {
|
|
956
|
-
let result = _out ?? [];
|
|
957
|
-
childrens ??= this.childrens;
|
|
958
|
-
if (childrens) {
|
|
959
|
-
for (let item of childrens) {
|
|
960
|
-
let findResult = filter(item);
|
|
961
|
-
if (findResult === true) {
|
|
962
|
-
result.push(item);
|
|
963
|
-
}
|
|
964
|
-
if (item.childrens) {
|
|
965
|
-
this.find(filter, item.childrens, result);
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
return result;
|
|
970
|
-
}
|
|
971
|
-
/**
|
|
972
|
-
* 是否包含
|
|
973
|
-
* @param filter 返回true则记录,返回false则跳过该元素的子集
|
|
974
|
-
* @returns
|
|
975
|
-
*/
|
|
976
|
-
contains(filter, childrens) {
|
|
977
|
-
childrens ??= this.childrens;
|
|
978
|
-
if (childrens) {
|
|
979
|
-
for (let item of childrens) {
|
|
980
|
-
let findResult = filter(item);
|
|
981
|
-
if (findResult === true) {
|
|
982
|
-
return true;
|
|
983
|
-
}
|
|
984
|
-
if (item.childrens && item.childrens.length) {
|
|
985
|
-
if (this.contains(filter, item.childrens)) {
|
|
986
|
-
return true;
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
}
|
|
991
|
-
return false;
|
|
992
|
-
}
|
|
993
|
-
}
|
|
994
|
-
VNode.Node = Node;
|
|
995
|
-
/**
|
|
996
|
-
* 根节点
|
|
997
|
-
*/
|
|
998
|
-
class Root extends Node {
|
|
999
|
-
childrens = [];
|
|
1000
|
-
component;
|
|
1001
|
-
constructor() {
|
|
1002
|
-
super();
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
VNode.Root = Root;
|
|
1006
|
-
/**
|
|
1007
|
-
* 文本类型节点
|
|
1008
|
-
*/
|
|
1009
|
-
class Text extends Node {
|
|
1010
|
-
text;
|
|
1011
|
-
static = true;
|
|
1012
|
-
constructor(text, parent) {
|
|
1013
|
-
super(parent);
|
|
1014
|
-
this.text = text;
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
VNode.Text = Text;
|
|
1018
|
-
/**
|
|
1019
|
-
* Html节点
|
|
1020
|
-
*/
|
|
1021
|
-
class Html extends Node {
|
|
1022
|
-
html;
|
|
1023
|
-
static = true;
|
|
1024
|
-
constructor(html, parent) {
|
|
1025
|
-
super(parent);
|
|
1026
|
-
this.html = html;
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
VNode.Html = Html;
|
|
1030
|
-
/**
|
|
1031
|
-
* 注释节点
|
|
1032
|
-
*/
|
|
1033
|
-
class Comment extends Node {
|
|
1034
|
-
text;
|
|
1035
|
-
static = true;
|
|
1036
|
-
constructor(text, parent) {
|
|
1037
|
-
super(parent);
|
|
1038
|
-
this.text = text;
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
VNode.Comment = Comment;
|
|
1042
|
-
/**
|
|
1043
|
-
* Element节点
|
|
1044
|
-
*/
|
|
1045
|
-
class Element extends Node {
|
|
1046
|
-
tagName;
|
|
1047
|
-
static = true;
|
|
1048
|
-
attributes = {};
|
|
1049
|
-
childrens = [];
|
|
1050
|
-
events = [];
|
|
1051
|
-
/**
|
|
1052
|
-
* 协助事件存储,用于存储辅助事件,例如outside等事件
|
|
1053
|
-
*/
|
|
1054
|
-
_assistEventCache;
|
|
1055
|
-
constructor(tagName, parent) {
|
|
1056
|
-
super(parent);
|
|
1057
|
-
this.tagName = tagName;
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
VNode.Element = Element;
|
|
1061
|
-
/**
|
|
1062
|
-
* 组件节点
|
|
1063
|
-
*/
|
|
1064
|
-
class Component extends Node {
|
|
1065
|
-
/** 组件名(template标签名) */
|
|
1066
|
-
name;
|
|
1067
|
-
/** 组件实例 */
|
|
1068
|
-
component;
|
|
1069
|
-
/** 事件 */
|
|
1070
|
-
events = [];
|
|
1071
|
-
/** 参数 */
|
|
1072
|
-
propValues = {};
|
|
1073
|
-
/** 是否保持存活 */
|
|
1074
|
-
keepalive;
|
|
1075
|
-
/**
|
|
1076
|
-
* 当前组件第一个element vnode
|
|
1077
|
-
*/
|
|
1078
|
-
get firstElement() {
|
|
1079
|
-
return this.childrens ? this.findElement(this.childrens) : undefined;
|
|
1080
|
-
}
|
|
1081
|
-
findElement(childrens) {
|
|
1082
|
-
for (let item of childrens) {
|
|
1083
|
-
if (item instanceof VNode.Element) {
|
|
1084
|
-
return item;
|
|
1085
|
-
}
|
|
1086
|
-
if (item.childrens) {
|
|
1087
|
-
let result = this.findElement(item.childrens);
|
|
1088
|
-
if (result)
|
|
1089
|
-
return result;
|
|
1090
|
-
}
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
VNode.Component = Component;
|
|
1095
|
-
/**
|
|
1096
|
-
* 条件节点
|
|
1097
|
-
*/
|
|
1098
|
-
class Condition extends Node {
|
|
1099
|
-
cmdName;
|
|
1100
|
-
result = false;
|
|
1101
|
-
childrens = [];
|
|
1102
|
-
isShow = false;
|
|
1103
|
-
constructor(cmdName, parent) {
|
|
1104
|
-
super(parent);
|
|
1105
|
-
this.cmdName = cmdName;
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
VNode.Condition = Condition;
|
|
1109
|
-
/**
|
|
1110
|
-
* 列表节点,内部包含多组列表项
|
|
1111
|
-
*/
|
|
1112
|
-
class List extends Node {
|
|
1113
|
-
childrens = [];
|
|
1114
|
-
}
|
|
1115
|
-
VNode.List = List;
|
|
1116
|
-
/**
|
|
1117
|
-
* 循环列表项
|
|
1118
|
-
*/
|
|
1119
|
-
class ListItem extends Node {
|
|
1120
|
-
ob;
|
|
1121
|
-
childrens = [];
|
|
1122
|
-
constructor(ob, parent) {
|
|
1123
|
-
super(parent);
|
|
1124
|
-
this.ob = ob;
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
VNode.ListItem = ListItem;
|
|
1128
|
-
/**
|
|
1129
|
-
* 插槽节点
|
|
1130
|
-
*/
|
|
1131
|
-
class RenderSection extends Node {
|
|
1132
|
-
id = "unknown";
|
|
1133
|
-
params = [];
|
|
1134
|
-
section;
|
|
1135
|
-
childrens = [];
|
|
1136
|
-
ob;
|
|
1137
|
-
constructor(idOrSection, parent) {
|
|
1138
|
-
super(parent);
|
|
1139
|
-
if (typeof idOrSection === "string") {
|
|
1140
|
-
this.id = idOrSection;
|
|
1141
|
-
}
|
|
1142
|
-
else {
|
|
1143
|
-
this.section = idOrSection;
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
}
|
|
1147
|
-
VNode.RenderSection = RenderSection;
|
|
1148
|
-
})(VNode || (VNode = {}));
|
|
1149
|
-
|
|
1150
|
-
const LOGTAG$4 = "DOM渲染";
|
|
1151
|
-
const TAG_PLAINTEXT_ELEMENT = ["script", "style", "textarea", "pre"];
|
|
1152
|
-
let eventSeed = 0;
|
|
1153
|
-
var Render;
|
|
1154
|
-
(function (Render) {
|
|
1155
|
-
/**
|
|
1156
|
-
* 注入TagId
|
|
1157
|
-
*/
|
|
1158
|
-
Render.IRENDERIOCTAGID = Symbol.for("JOKER_IRENDERIOC_TAGID");
|
|
1159
|
-
/**
|
|
1160
|
-
* 默认Render,采用H5-DOM模式进行输出
|
|
1161
|
-
*/
|
|
1162
|
-
class DomRender {
|
|
1163
|
-
elements;
|
|
1164
|
-
constructor() {
|
|
1165
|
-
this.elements = document.createDocumentFragment();
|
|
1166
|
-
}
|
|
1167
|
-
mount(root) {
|
|
1168
|
-
if (root instanceof Element) {
|
|
1169
|
-
root.appendChild(this.elements);
|
|
1170
|
-
}
|
|
1171
|
-
else if (root instanceof VNode.Component) {
|
|
1172
|
-
if (root.parent) {
|
|
1173
|
-
if (root.output) {
|
|
1174
|
-
let nodeEl = root.output;
|
|
1175
|
-
let parentEl = getVNodeAppendToContainer(root) || nodeEl.parentNode;
|
|
1176
|
-
//不会出现没有parentEl的场景
|
|
1177
|
-
if (parentEl) {
|
|
1178
|
-
parentEl.insertBefore(this.elements, nodeEl);
|
|
1179
|
-
}
|
|
1180
|
-
}
|
|
1181
|
-
else {
|
|
1182
|
-
logger.error(LOGTAG$4, "组件挂载渲染时发现该节点未定义DOM定位节点", root);
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
else {
|
|
1186
|
-
logger.error(LOGTAG$4, "mount子组件时,发现该组件无父级", root);
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1189
|
-
else {
|
|
1190
|
-
logger.error(LOGTAG$4, "mount只支持挂载到Element或VNode.Node类型数据中", root);
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
appendNode(node) {
|
|
1194
|
-
this.renderNode(node);
|
|
1195
|
-
if (node.output) {
|
|
1196
|
-
let nodes = node.output instanceof HTMLCollection ||
|
|
1197
|
-
node.output instanceof NodeList ||
|
|
1198
|
-
Array.isArray(node.output)
|
|
1199
|
-
? Array.from(node.output)
|
|
1200
|
-
: [node.output];
|
|
1201
|
-
for (let item of nodes) {
|
|
1202
|
-
this.appendNodeChildren(node, item, node.parent);
|
|
1203
|
-
}
|
|
1204
|
-
return;
|
|
1205
|
-
}
|
|
1206
|
-
logger.error(LOGTAG$4, "未找自身节点的el属性,无法进行dom挂载", node);
|
|
1207
|
-
}
|
|
1208
|
-
updateNode(node, propertyKey) {
|
|
1209
|
-
if (node instanceof VNode.Element) {
|
|
1210
|
-
for (let attrName in node.attributes) {
|
|
1211
|
-
let attrVal = node.attributes[attrName];
|
|
1212
|
-
this.setAttribute(node.output, attrName, attrVal);
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
else if (node instanceof VNode.Text) {
|
|
1216
|
-
if (node.parent &&
|
|
1217
|
-
node.parent instanceof VNode.Element &&
|
|
1218
|
-
TAG_PLAINTEXT_ELEMENT.includes(node.parent.tagName)) {
|
|
1219
|
-
this.removeNode(node);
|
|
1220
|
-
this.appendNode(node);
|
|
1221
|
-
}
|
|
1222
|
-
else {
|
|
1223
|
-
node.output.textContent = escape2Html(node.text || "");
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1226
|
-
else if (node instanceof VNode.Html) {
|
|
1227
|
-
node.output.root.innerHTML = node.html;
|
|
1228
|
-
}
|
|
1229
|
-
else {
|
|
1230
|
-
logger.error(LOGTAG$4, `该节点不支持${propertyKey}的更新`, node);
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
removeNode(node, reserveOutPut) {
|
|
1234
|
-
let domNodes = node.output instanceof HTMLCollection || node.output instanceof NodeList || Array.isArray(node.output)
|
|
1235
|
-
? Array.from(node.output)
|
|
1236
|
-
: [node.output];
|
|
1237
|
-
//可能是root等无根的节点
|
|
1238
|
-
domNodes?.forEach((item) => {
|
|
1239
|
-
item?.remove();
|
|
1240
|
-
});
|
|
1241
|
-
if (!reserveOutPut) {
|
|
1242
|
-
//element 元素 需要清除辅助事件
|
|
1243
|
-
node instanceof VNode.Element && removeAssistEvent(node);
|
|
1244
|
-
node.output = undefined;
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
destroy() {
|
|
1248
|
-
this.elements = undefined;
|
|
1249
|
-
}
|
|
1250
|
-
elementToEnter(node, name, type, callBack) {
|
|
1251
|
-
if (!node.output)
|
|
1252
|
-
return;
|
|
1253
|
-
this.transitionFrame(node, name, "enter", type, callBack);
|
|
1254
|
-
}
|
|
1255
|
-
elementToLeave(node, name, type, callBack) {
|
|
1256
|
-
if (!node.output)
|
|
1257
|
-
return;
|
|
1258
|
-
this.transitionFrame(node, name, "leave", type, callBack);
|
|
1259
|
-
}
|
|
1260
|
-
triggerEvent(node, _eventName, _e) {
|
|
1261
|
-
let removeEvent = [];
|
|
1262
|
-
for (let item of node.events) {
|
|
1263
|
-
let [eventName, event] = item;
|
|
1264
|
-
if (eventName === _eventName) {
|
|
1265
|
-
let isSelf = event.modifiers?.includes("self");
|
|
1266
|
-
let isOutSide = event.modifiers?.includes("outside");
|
|
1267
|
-
if (isSelf || isOutSide) {
|
|
1268
|
-
logger.warn(LOGTAG$4, "事件修饰符:self、outside在组件事件中无法使用,组件无法确认元素", node);
|
|
1269
|
-
continue;
|
|
1270
|
-
}
|
|
1271
|
-
let e = _e.event;
|
|
1272
|
-
if ((e instanceof KeyboardEvent && ["keydown", "keypress", "keyup"].includes(eventName)) ||
|
|
1273
|
-
(e instanceof MouseEvent && ["click", "dbclick", "mouseup", "mousedown"].includes(eventName))) {
|
|
1274
|
-
if (checkEventModifier(e, event.modifiers) === false)
|
|
1275
|
-
continue;
|
|
1276
|
-
}
|
|
1277
|
-
event.callBack(_e);
|
|
1278
|
-
if (event.modifiers?.includes("prevent")) {
|
|
1279
|
-
_e.preventDefault();
|
|
1280
|
-
}
|
|
1281
|
-
if (event.modifiers?.includes("once")) {
|
|
1282
|
-
removeEvent.push(item);
|
|
1283
|
-
}
|
|
1284
|
-
if (event.modifiers?.includes("stop")) {
|
|
1285
|
-
_e.stopPropagation();
|
|
1286
|
-
return false;
|
|
1287
|
-
}
|
|
1288
|
-
}
|
|
1289
|
-
}
|
|
1290
|
-
//剔除需要移除的事件
|
|
1291
|
-
if (removeEvent.length) {
|
|
1292
|
-
removeEvent.forEach((e) => {
|
|
1293
|
-
remove(node.events, e);
|
|
1294
|
-
});
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
//#region 私有实现
|
|
1298
|
-
transitionFrame(node, transitionName, model, type, callBack) {
|
|
1299
|
-
addClassName(node, getTransitionClassName(transitionName, model, "from"));
|
|
1300
|
-
type ||= "transition";
|
|
1301
|
-
let id = (node.output.__TRANSITION_EVNETID__ = eventSeed++);
|
|
1302
|
-
// 在下一帧执行的时候移除class
|
|
1303
|
-
requestAnimationFrame(() => {
|
|
1304
|
-
requestAnimationFrame(() => {
|
|
1305
|
-
if (!node.output)
|
|
1306
|
-
return;
|
|
1307
|
-
addClassName(node, getTransitionClassName(transitionName, model, "active"));
|
|
1308
|
-
removeClassName(node, getTransitionClassName(transitionName, model, "from"));
|
|
1309
|
-
addClassName(node, getTransitionClassName(transitionName, model, "to"));
|
|
1310
|
-
let transitionInfo = getTransitionInfo(node.output, type);
|
|
1311
|
-
if (!transitionInfo) {
|
|
1312
|
-
callBack?.();
|
|
1313
|
-
return;
|
|
1314
|
-
}
|
|
1315
|
-
let ended = 0;
|
|
1316
|
-
// 定义一个供addEventListener执行的回调函数
|
|
1317
|
-
let resolve = () => {
|
|
1318
|
-
removeClassName(node, getTransitionClassName(transitionName, model, "to"));
|
|
1319
|
-
removeClassName(node, getTransitionClassName(transitionName, model, "active"));
|
|
1320
|
-
//可能存在越级删除,造成动画元素过早移除,
|
|
1321
|
-
if (!node.output)
|
|
1322
|
-
return;
|
|
1323
|
-
node.output.removeEventListener(`${type}end`, onEnd);
|
|
1324
|
-
if (id === node.output.__TRANSITION_EVNETID__) {
|
|
1325
|
-
callBack?.();
|
|
1326
|
-
}
|
|
1327
|
-
};
|
|
1328
|
-
let onEnd = (e) => {
|
|
1329
|
-
if (e.target === node.output && ++ended >= transitionInfo.count) {
|
|
1330
|
-
resolve();
|
|
1331
|
-
}
|
|
1332
|
-
};
|
|
1333
|
-
setTimeout(() => {
|
|
1334
|
-
if (ended < transitionInfo.count) {
|
|
1335
|
-
resolve();
|
|
1336
|
-
}
|
|
1337
|
-
}, transitionInfo.timeout + 1);
|
|
1338
|
-
// 监听动效结束事件,type由props传入
|
|
1339
|
-
node.output?.addEventListener(`${type}end`, onEnd);
|
|
1340
|
-
});
|
|
1341
|
-
});
|
|
1342
|
-
}
|
|
1343
|
-
renderNode(node) {
|
|
1344
|
-
if (node.output)
|
|
1345
|
-
return;
|
|
1346
|
-
if (node instanceof VNode.Text) {
|
|
1347
|
-
if (node.parent &&
|
|
1348
|
-
node.parent instanceof VNode.Element &&
|
|
1349
|
-
TAG_PLAINTEXT_ELEMENT.includes(node.parent.tagName)) {
|
|
1350
|
-
node.output = this.parserHtml(node.text);
|
|
1351
|
-
}
|
|
1352
|
-
else {
|
|
1353
|
-
node.output = document.createTextNode(escape2Html(node.text || ""));
|
|
1354
|
-
}
|
|
1355
|
-
}
|
|
1356
|
-
else if (node instanceof VNode.Html) {
|
|
1357
|
-
let conatiner = document.createElement("joker-html-container");
|
|
1358
|
-
//@ts-ignore
|
|
1359
|
-
conatiner.JOKER_NODE = node;
|
|
1360
|
-
conatiner.root.innerHTML = node.html;
|
|
1361
|
-
node.output = conatiner;
|
|
1362
|
-
}
|
|
1363
|
-
else if (node instanceof VNode.Element) {
|
|
1364
|
-
let element;
|
|
1365
|
-
//@ts-ignore
|
|
1366
|
-
if (node.tagName === "svg" || node.parent.isSvg) {
|
|
1367
|
-
//@ts-ignore
|
|
1368
|
-
node.isSvg = true;
|
|
1369
|
-
element = document.createElementNS("http://www.w3.org/2000/svg", node.tagName);
|
|
1370
|
-
}
|
|
1371
|
-
else {
|
|
1372
|
-
element = document.createElement(node.tagName);
|
|
1373
|
-
}
|
|
1374
|
-
for (let attrName in node.attributes) {
|
|
1375
|
-
this.setAttribute(element, attrName, node.attributes[attrName]);
|
|
1376
|
-
}
|
|
1377
|
-
//@ts-ignore
|
|
1378
|
-
element.JOKER_NODE = node;
|
|
1379
|
-
node.output = element;
|
|
1380
|
-
//做穿透延迟仅对outside.click
|
|
1381
|
-
if (node.events.some((n) => n[0] === "click" && n[1].modifiers?.includes("outside"))) {
|
|
1382
|
-
//宏任务
|
|
1383
|
-
setTimeout(() => {
|
|
1384
|
-
this.initElementEvents(element, node);
|
|
1385
|
-
});
|
|
1386
|
-
}
|
|
1387
|
-
else {
|
|
1388
|
-
this.initElementEvents(element, node);
|
|
1389
|
-
}
|
|
1390
|
-
}
|
|
1391
|
-
else if (node instanceof VNode.Comment) {
|
|
1392
|
-
node.output = document.createComment(node.text);
|
|
1393
|
-
}
|
|
1394
|
-
else {
|
|
1395
|
-
node.output = document.createTextNode("");
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
initElementEvents(el, node) {
|
|
1399
|
-
for (let [eventName, event] of node.events) {
|
|
1400
|
-
let isSelf = event.modifiers?.includes("self");
|
|
1401
|
-
let isOutSide = event.modifiers?.includes("outside");
|
|
1402
|
-
if (isSelf && isOutSide) {
|
|
1403
|
-
logger.warn(LOGTAG$4, "事件修饰符:self、outside不可以同时存在,将按照self处理", node);
|
|
1404
|
-
isOutSide = false;
|
|
1405
|
-
}
|
|
1406
|
-
let eventCallBack = function (e) {
|
|
1407
|
-
//节点睡眠时,不做事件传递和广播
|
|
1408
|
-
if (node.sleep)
|
|
1409
|
-
return;
|
|
1410
|
-
/**
|
|
1411
|
-
* self : 必须是本身
|
|
1412
|
-
* prevent : 阻止系统
|
|
1413
|
-
* stop : 阻止冒泡
|
|
1414
|
-
* once : 只触发一次
|
|
1415
|
-
* outside : 外围时触发
|
|
1416
|
-
*/
|
|
1417
|
-
if (isSelf) {
|
|
1418
|
-
//不是自身时不执行
|
|
1419
|
-
if (e.target !== el) {
|
|
1420
|
-
return;
|
|
1421
|
-
}
|
|
1422
|
-
}
|
|
1423
|
-
if (isOutSide) {
|
|
1424
|
-
//是自身时不执行
|
|
1425
|
-
if (e.target === el || el.contains(e.target)) {
|
|
1426
|
-
return;
|
|
1427
|
-
}
|
|
1428
|
-
//空冒泡事件
|
|
1429
|
-
if (document.contains(e.target) === false)
|
|
1430
|
-
return;
|
|
1431
|
-
//append-to时,dom层级无法确认
|
|
1432
|
-
if (node.contains((n) => {
|
|
1433
|
-
let nodes = n.output instanceof HTMLCollection ||
|
|
1434
|
-
n.output instanceof NodeList ||
|
|
1435
|
-
Array.isArray(n.output)
|
|
1436
|
-
? Array.from(n.output)
|
|
1437
|
-
: [n.output];
|
|
1438
|
-
return nodes.includes(e.target);
|
|
1439
|
-
})) {
|
|
1440
|
-
return true;
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
if ((e instanceof KeyboardEvent && ["keydown", "keypress", "keyup"].includes(eventName)) ||
|
|
1444
|
-
(e instanceof MouseEvent && ["click", "dbclick", "mouseup", "mousedown"].includes(eventName))) {
|
|
1445
|
-
if (checkEventModifier(e, event.modifiers) === false)
|
|
1446
|
-
return;
|
|
1447
|
-
}
|
|
1448
|
-
event.callBack({
|
|
1449
|
-
eventName,
|
|
1450
|
-
event: e,
|
|
1451
|
-
/**目标元素 */
|
|
1452
|
-
target: node,
|
|
1453
|
-
/** 阻止默认事件 */
|
|
1454
|
-
preventDefault: () => e.preventDefault(),
|
|
1455
|
-
/** 阻止事件传播 */
|
|
1456
|
-
stopPropagation: () => e.stopPropagation(),
|
|
1457
|
-
data: undefined
|
|
1458
|
-
});
|
|
1459
|
-
if (event.modifiers?.includes("prevent")) {
|
|
1460
|
-
e.preventDefault();
|
|
1461
|
-
}
|
|
1462
|
-
if (event.modifiers?.includes("stop")) {
|
|
1463
|
-
e.stopPropagation();
|
|
1464
|
-
}
|
|
1465
|
-
if (event.modifiers?.includes("once")) {
|
|
1466
|
-
if (isOutSide) {
|
|
1467
|
-
removeAssistEvent(node, eventName, eventCallBack);
|
|
1468
|
-
}
|
|
1469
|
-
else {
|
|
1470
|
-
el.removeEventListener(eventName, eventCallBack);
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
};
|
|
1474
|
-
let eventOpt = undefined;
|
|
1475
|
-
if (event.modifiers?.includes("passive")) {
|
|
1476
|
-
eventOpt = {
|
|
1477
|
-
passive: true
|
|
1478
|
-
};
|
|
1479
|
-
}
|
|
1480
|
-
if (isOutSide) {
|
|
1481
|
-
registoryAssistEvent(node, eventName, eventCallBack, eventOpt);
|
|
1482
|
-
}
|
|
1483
|
-
else {
|
|
1484
|
-
el.addEventListener(eventName, eventCallBack, eventOpt);
|
|
1485
|
-
}
|
|
1486
|
-
}
|
|
1487
|
-
}
|
|
1488
|
-
parserHtml(str) {
|
|
1489
|
-
var tempContainer = document.createElement("div");
|
|
1490
|
-
tempContainer.innerHTML = str;
|
|
1491
|
-
return tempContainer.childNodes;
|
|
1492
|
-
}
|
|
1493
|
-
isCommandGroup(node) {
|
|
1494
|
-
return (node instanceof VNode.Component ||
|
|
1495
|
-
node instanceof VNode.Condition ||
|
|
1496
|
-
node instanceof VNode.List ||
|
|
1497
|
-
node instanceof VNode.ListItem ||
|
|
1498
|
-
node instanceof VNode.RenderSection);
|
|
1499
|
-
}
|
|
1500
|
-
appendNodeChildren(node, element, parent) {
|
|
1501
|
-
let parentEl = getVNodeAppendToContainer(node);
|
|
1502
|
-
if (parentEl) {
|
|
1503
|
-
parentEl.appendChild(element);
|
|
1504
|
-
return;
|
|
1505
|
-
}
|
|
1506
|
-
if (parent === undefined) {
|
|
1507
|
-
//根节点+appendTo
|
|
1508
|
-
this.elements.appendChild(element);
|
|
1509
|
-
}
|
|
1510
|
-
else if (parent) {
|
|
1511
|
-
if (parent instanceof VNode.Root) {
|
|
1512
|
-
//root上是VNode.Componet容器
|
|
1513
|
-
let containerParent = parent.parent;
|
|
1514
|
-
if (containerParent && containerParent instanceof VNode.Component) {
|
|
1515
|
-
//这种场景一般只使用与weakup时再挂载
|
|
1516
|
-
if (containerParent.output) {
|
|
1517
|
-
let nodeEl = containerParent.output;
|
|
1518
|
-
let parentEl = nodeEl.parentNode;
|
|
1519
|
-
//不会出现没有parentEl的场景
|
|
1520
|
-
if (parentEl) {
|
|
1521
|
-
parentEl.insertBefore(element, nodeEl);
|
|
1522
|
-
return;
|
|
1523
|
-
}
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1526
|
-
//全部兜底,是存在组件内直接是命令的场景,会出现parent.parent还未挂载
|
|
1527
|
-
//该场景应算顺序执行的产物
|
|
1528
|
-
this.elements.appendChild(element);
|
|
1529
|
-
}
|
|
1530
|
-
else if (parent instanceof VNode.Element) {
|
|
1531
|
-
let parentEl = parent.output;
|
|
1532
|
-
if (parentEl === undefined) {
|
|
1533
|
-
logger.error(LOGTAG$4, "appendNodeChildren挂载失败,找不到父节点DOM输出", { parent, node });
|
|
1534
|
-
}
|
|
1535
|
-
parentEl.appendChild(element);
|
|
1536
|
-
}
|
|
1537
|
-
else if (this.isCommandGroup(parent)) {
|
|
1538
|
-
let nodeEl = parent.output;
|
|
1539
|
-
//如果if 或者 for循环中存在 append-to 则直接向body输出,不考虑body输出顺序
|
|
1540
|
-
let parentEl = nodeEl.parentNode;
|
|
1541
|
-
//不会出现没有parentEl的场景
|
|
1542
|
-
if (parentEl) {
|
|
1543
|
-
parentEl.insertBefore(element, nodeEl);
|
|
1544
|
-
}
|
|
1545
|
-
}
|
|
1546
|
-
else {
|
|
1547
|
-
logger.error(LOGTAG$4, `该节点不支持嵌套子集,请检查。`, { node, parent });
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1551
|
-
setAttribute(el, attrName, attrVal) {
|
|
1552
|
-
if (typeof attrVal === "boolean") {
|
|
1553
|
-
//如果是boolean,则做新增和删除特性处理
|
|
1554
|
-
if (attrVal) {
|
|
1555
|
-
el.setAttribute(attrName, "");
|
|
1556
|
-
}
|
|
1557
|
-
else {
|
|
1558
|
-
el.removeAttribute(attrName);
|
|
1559
|
-
}
|
|
1560
|
-
return;
|
|
1561
|
-
}
|
|
1562
|
-
if (attrName === "class") {
|
|
1563
|
-
if (Array.isArray(attrVal)) {
|
|
1564
|
-
let newClass = [];
|
|
1565
|
-
for (let val of attrVal) {
|
|
1566
|
-
if (isObject(val)) {
|
|
1567
|
-
for (let name in val) {
|
|
1568
|
-
if (val[name]) {
|
|
1569
|
-
newClass.push(name);
|
|
1570
|
-
}
|
|
1571
|
-
}
|
|
1572
|
-
}
|
|
1573
|
-
else {
|
|
1574
|
-
val && newClass.push(val);
|
|
1575
|
-
}
|
|
1576
|
-
}
|
|
1577
|
-
attrVal = newClass.join(" ");
|
|
1578
|
-
}
|
|
1579
|
-
else if (isObject(attrVal)) {
|
|
1580
|
-
for (let name in attrVal) {
|
|
1581
|
-
if (attrVal[name]) {
|
|
1582
|
-
el.classList.add(name);
|
|
1583
|
-
}
|
|
1584
|
-
else {
|
|
1585
|
-
el.classList.remove(name);
|
|
1586
|
-
}
|
|
1587
|
-
}
|
|
1588
|
-
return;
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
else if (attrName === "style" && isObject(attrVal)) {
|
|
1592
|
-
el.removeAttribute("style");
|
|
1593
|
-
for (let name in attrVal) {
|
|
1594
|
-
let isEmptyValue = false;
|
|
1595
|
-
if (attrVal[name] === undefined || attrVal[name] === false) {
|
|
1596
|
-
isEmptyValue = true;
|
|
1597
|
-
}
|
|
1598
|
-
let val = String(attrVal[name]);
|
|
1599
|
-
if (isEmptyStr(val)) {
|
|
1600
|
-
isEmptyValue = true;
|
|
1601
|
-
}
|
|
1602
|
-
//非空
|
|
1603
|
-
if (!isEmptyValue) {
|
|
1604
|
-
//@ts-ignore
|
|
1605
|
-
el.style[name] = val;
|
|
1606
|
-
}
|
|
1607
|
-
}
|
|
1608
|
-
return;
|
|
1609
|
-
}
|
|
1610
|
-
attrVal = (attrVal ?? "").toString().trim();
|
|
1611
|
-
if (attrName === "class") {
|
|
1612
|
-
attrVal = attrVal
|
|
1613
|
-
.split(/\s/)
|
|
1614
|
-
.filter((m) => m.trim())
|
|
1615
|
-
.join(" ");
|
|
1616
|
-
}
|
|
1617
|
-
if (attrName === "value" && "value" in el) {
|
|
1618
|
-
el.value = attrVal;
|
|
1619
|
-
}
|
|
1620
|
-
else {
|
|
1621
|
-
el.setAttribute(attrName, attrVal);
|
|
1622
|
-
}
|
|
1623
|
-
}
|
|
1624
|
-
}
|
|
1625
|
-
Render.DomRender = DomRender;
|
|
1626
|
-
})(Render || (Render = {}));
|
|
1627
|
-
function getTransitionClassName(transition, mode, type) {
|
|
1628
|
-
return `${transition}-${mode}-${type}`;
|
|
1629
|
-
}
|
|
1630
|
-
/**
|
|
1631
|
-
* 注册协助事件,用于做outside等全局事件记录
|
|
1632
|
-
*/
|
|
1633
|
-
function registoryAssistEvent(node, eventName, eventCallBack, eventOpt) {
|
|
1634
|
-
node._assistEventCache ??= [];
|
|
1635
|
-
node._assistEventCache.push([eventName, eventCallBack]);
|
|
1636
|
-
document.body.addEventListener(eventName, eventCallBack, eventOpt);
|
|
1637
|
-
}
|
|
1638
|
-
function removeAssistEvent(node, eventName, eventCallBack) {
|
|
1639
|
-
if (node._assistEventCache && eventName && eventCallBack) {
|
|
1640
|
-
removeFilter(node._assistEventCache, (m) => {
|
|
1641
|
-
return m[0] === eventName && m[1] === eventCallBack;
|
|
1642
|
-
});
|
|
1643
|
-
document.body.removeEventListener(eventName, eventCallBack);
|
|
1644
|
-
}
|
|
1645
|
-
else {
|
|
1646
|
-
node._assistEventCache?.forEach((m) => {
|
|
1647
|
-
document.body.removeEventListener(m[0], m[1]);
|
|
1648
|
-
});
|
|
1649
|
-
node._assistEventCache && (node._assistEventCache.length = 0);
|
|
1650
|
-
node._assistEventCache = undefined;
|
|
1651
|
-
}
|
|
1652
|
-
}
|
|
1653
|
-
const keyEventModifierNative = {
|
|
1654
|
-
enter: "enter",
|
|
1655
|
-
backspace: "delete",
|
|
1656
|
-
tab: "tab",
|
|
1657
|
-
arrowup: "up",
|
|
1658
|
-
arrowdown: "down",
|
|
1659
|
-
arrowleft: "left",
|
|
1660
|
-
arrowright: "right",
|
|
1661
|
-
escape: "esc",
|
|
1662
|
-
" ": "space"
|
|
1663
|
-
};
|
|
1664
|
-
function checkEventModifier(e, modifiers) {
|
|
1665
|
-
if (e instanceof KeyboardEvent) {
|
|
1666
|
-
if (e.key === undefined)
|
|
1667
|
-
return false;
|
|
1668
|
-
for (let name in keyEventModifierNative) {
|
|
1669
|
-
//当有修饰约束 && 约束不成立 则return false 终止
|
|
1670
|
-
if (
|
|
1671
|
-
//@ts-ignore
|
|
1672
|
-
modifiers?.includes(keyEventModifierNative[name]) &&
|
|
1673
|
-
e.key.toLowerCase() !== name)
|
|
1674
|
-
return false;
|
|
1675
|
-
}
|
|
1676
|
-
}
|
|
1677
|
-
else {
|
|
1678
|
-
if (modifiers?.includes("left") && e.button !== 0)
|
|
1679
|
-
return false;
|
|
1680
|
-
if (modifiers?.includes("right") && e.button !== 2)
|
|
1681
|
-
return false;
|
|
1682
|
-
if (modifiers?.includes("middle") && e.button !== 1)
|
|
1683
|
-
return false;
|
|
1684
|
-
}
|
|
1685
|
-
if (modifiers?.includes("ctrl") && e.ctrlKey === false)
|
|
1686
|
-
return false;
|
|
1687
|
-
if (modifiers?.includes("alt") && e.altKey === false)
|
|
1688
|
-
return false;
|
|
1689
|
-
if (modifiers?.includes("shift") && e.shiftKey === false)
|
|
1690
|
-
return false;
|
|
1691
|
-
return true;
|
|
1692
|
-
}
|
|
1693
|
-
function addClassName(node, className) {
|
|
1694
|
-
if (!node.output)
|
|
1695
|
-
return;
|
|
1696
|
-
node.output.classList.add(className);
|
|
1697
|
-
}
|
|
1698
|
-
function removeClassName(node, className) {
|
|
1699
|
-
if (!node.output)
|
|
1700
|
-
return;
|
|
1701
|
-
node.output.classList.remove(className);
|
|
1702
|
-
}
|
|
1703
|
-
function getVNodeAppendToContainer(node) {
|
|
1704
|
-
if (node instanceof VNode.Element || node instanceof VNode.Component) {
|
|
1705
|
-
let appendTo = node instanceof VNode.Component ? node.propValues["append-to"] : node.attributes["append-to"];
|
|
1706
|
-
if (appendTo) {
|
|
1707
|
-
if (appendTo instanceof VNode.Element) {
|
|
1708
|
-
return appendTo.output;
|
|
1709
|
-
}
|
|
1710
|
-
else if (typeof appendTo === "string") {
|
|
1711
|
-
let dom = document.querySelector(appendTo);
|
|
1712
|
-
if (dom)
|
|
1713
|
-
return dom;
|
|
1714
|
-
}
|
|
1715
|
-
logger.warn(LOGTAG$4, "appendTo类型不支持", { appendTo, node });
|
|
1716
|
-
}
|
|
1717
|
-
}
|
|
1718
|
-
}
|
|
1719
|
-
function getTransitionInfo(el, type) {
|
|
1720
|
-
let styles = window.getComputedStyle(el);
|
|
1721
|
-
let getStyleProperties = (key) => (styles[key] || "").split(", ");
|
|
1722
|
-
if (type === "transition") {
|
|
1723
|
-
let delays = getStyleProperties("transitionDelay");
|
|
1724
|
-
let durations = getStyleProperties("transitionDuration");
|
|
1725
|
-
let timeout = getTimeout(delays, durations);
|
|
1726
|
-
if (timeout > 0) {
|
|
1727
|
-
return {
|
|
1728
|
-
timeout,
|
|
1729
|
-
count: durations.length
|
|
1730
|
-
};
|
|
1731
|
-
}
|
|
1732
|
-
}
|
|
1733
|
-
else if (type === "animation") {
|
|
1734
|
-
let delays = getStyleProperties("animationDelay");
|
|
1735
|
-
let durations = getStyleProperties("animationDuration");
|
|
1736
|
-
let timeout = getTimeout(delays, durations);
|
|
1737
|
-
if (timeout > 0) {
|
|
1738
|
-
return {
|
|
1739
|
-
timeout,
|
|
1740
|
-
count: durations.length
|
|
1741
|
-
};
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
}
|
|
1745
|
-
function getTimeout(delays, durations) {
|
|
1746
|
-
while (delays.length < durations.length) {
|
|
1747
|
-
delays.concat(delays);
|
|
1748
|
-
}
|
|
1749
|
-
return Math.max(...durations.map((d, i) => toMs(d) + toMs(delays[i])));
|
|
1750
|
-
}
|
|
1751
|
-
function toMs(s) {
|
|
1752
|
-
if (s === "auto")
|
|
1753
|
-
return 0;
|
|
1754
|
-
return Number(s.slice(0, -1).replace(",", ".")) * 1000;
|
|
1755
|
-
}
|
|
1756
|
-
// 创建一个自定义元素
|
|
1757
|
-
class HtmlContainerWebComponent extends HTMLElement {
|
|
1758
|
-
root;
|
|
1759
|
-
constructor() {
|
|
1760
|
-
super();
|
|
1761
|
-
this.root = this.attachShadow({ mode: "open" });
|
|
1762
|
-
}
|
|
1763
|
-
}
|
|
1764
|
-
// 注册自定义元素
|
|
1765
|
-
!customElements.get("joker-html-container") && customElements.define("joker-html-container", HtmlContainerWebComponent);
|
|
1766
|
-
|
|
1767
|
-
//全局方法
|
|
1768
|
-
const __GLONAL_FUNTIONS__ = {};
|
|
1769
|
-
/**
|
|
1770
|
-
* 注册全局组件
|
|
1771
|
-
* @param components 组件
|
|
1772
|
-
*/
|
|
1773
|
-
function registerGlobalFunction(filters) {
|
|
1774
|
-
for (let name in filters) {
|
|
1775
|
-
__GLONAL_FUNTIONS__[name] = filters[name];
|
|
1776
|
-
}
|
|
1777
|
-
}
|
|
1778
|
-
|
|
1779
|
-
const GLOBAL_TAG = "Global";
|
|
1780
|
-
const LOGTAG$3 = "渲染核心";
|
|
1781
|
-
/**
|
|
1782
|
-
* 创建表达式运行方法
|
|
1783
|
-
* @param express 表达式字符串(依赖AST转换,自带参数文根)
|
|
1784
|
-
* @returns
|
|
1785
|
-
*/
|
|
1786
|
-
function createExpress$1(express) {
|
|
1787
|
-
try {
|
|
1788
|
-
return new Function(EXPRESSHANDLERTAG, GLOBAL_TAG, `return ${express};`);
|
|
1789
|
-
}
|
|
1790
|
-
catch {
|
|
1791
|
-
throw new Error(`创建表达式运行方法时出现未知错误,表达式为` + express);
|
|
1792
|
-
}
|
|
1793
|
-
}
|
|
1794
|
-
class IParser {
|
|
1795
|
-
ast;
|
|
1796
|
-
ob;
|
|
1797
|
-
parent;
|
|
1798
|
-
ext;
|
|
1799
|
-
/** 当前转换节点ref标记 */
|
|
1800
|
-
ref = "";
|
|
1801
|
-
/** 当前AST解析 所产生的观察者 */
|
|
1802
|
-
watchers = [];
|
|
1803
|
-
node;
|
|
1804
|
-
constructor(
|
|
1805
|
-
/** ast集合 */
|
|
1806
|
-
ast,
|
|
1807
|
-
/** 数据源 会在component上进行属性新增 */
|
|
1808
|
-
ob,
|
|
1809
|
-
/** 父节点 */
|
|
1810
|
-
parent,
|
|
1811
|
-
/** 外部处理(ParserTemplate) */
|
|
1812
|
-
ext) {
|
|
1813
|
-
this.ast = ast;
|
|
1814
|
-
this.ob = ob;
|
|
1815
|
-
this.parent = parent;
|
|
1816
|
-
this.ext = ext;
|
|
1817
|
-
this.parser();
|
|
1818
|
-
this.afterParser();
|
|
1819
|
-
}
|
|
1820
|
-
beforeDestroy(keepalive) { }
|
|
1821
|
-
/**
|
|
1822
|
-
* 销毁流程
|
|
1823
|
-
*/
|
|
1824
|
-
destroy(keepalive) {
|
|
1825
|
-
//优先移除watcher关系
|
|
1826
|
-
this.clearWatchers();
|
|
1827
|
-
if (this.parent.childrens && this.node) {
|
|
1828
|
-
if (this.node instanceof VNode.Element || this.node instanceof VNode.Component) {
|
|
1829
|
-
//如果是Element 或者 组件节点(只有这些类型可以配置ref)
|
|
1830
|
-
this.ext.removeRef(this.node);
|
|
1831
|
-
}
|
|
1832
|
-
let removeNode = () => {
|
|
1833
|
-
if (this.parent && this.node) {
|
|
1834
|
-
this.beforeDestroy(keepalive);
|
|
1835
|
-
this.destroyChildrens(keepalive);
|
|
1836
|
-
//remove 应该按照append倒序执行
|
|
1837
|
-
this.ext.render?.removeNode(this.node);
|
|
1838
|
-
this.parent.childrens && remove(this.parent.childrens, this.node);
|
|
1839
|
-
//通知放最后
|
|
1840
|
-
this.notifyNodeWatcher("remove");
|
|
1841
|
-
this.destroyOtherData();
|
|
1842
|
-
}
|
|
1843
|
-
};
|
|
1844
|
-
//如果有动画
|
|
1845
|
-
if (this.ext.nodeTransition(this.node, "leave", undefined, () => {
|
|
1846
|
-
removeNode();
|
|
1847
|
-
})) {
|
|
1848
|
-
//先解除层级关系,不阻塞其余节点正常卸载
|
|
1849
|
-
remove(this.parent.childrens, this.node);
|
|
1850
|
-
//消除所有子集的watcher监听
|
|
1851
|
-
this.destroyChildrensWatcher(this.node);
|
|
1852
|
-
return;
|
|
1853
|
-
}
|
|
1854
|
-
removeNode();
|
|
1855
|
-
}
|
|
1856
|
-
else {
|
|
1857
|
-
this.destroyOtherData();
|
|
1858
|
-
}
|
|
1859
|
-
}
|
|
1860
|
-
destroyOtherData() {
|
|
1861
|
-
this.node && (this.node[VNode.PARSERKEY] = undefined);
|
|
1862
|
-
this.node = undefined;
|
|
1863
|
-
this.parent = undefined;
|
|
1864
|
-
}
|
|
1865
|
-
/**
|
|
1866
|
-
* 销毁所有子集VNode
|
|
1867
|
-
*/
|
|
1868
|
-
destroyChildrens(keepalive) {
|
|
1869
|
-
while (this.node?.childrens?.length) {
|
|
1870
|
-
let item = this.node.childrens[0];
|
|
1871
|
-
if (item[VNode.PARSERKEY]) {
|
|
1872
|
-
item[VNode.PARSERKEY].destroy(keepalive);
|
|
1873
|
-
}
|
|
1874
|
-
else {
|
|
1875
|
-
//root 类型 ,不做销毁,只是做数组移除,销毁已处理
|
|
1876
|
-
remove(this.node.childrens, item);
|
|
1877
|
-
}
|
|
1878
|
-
}
|
|
1879
|
-
}
|
|
1880
|
-
/**
|
|
1881
|
-
* 销毁所有子集VNode的watcher,为了防止延迟卸载时,无效通知广播
|
|
1882
|
-
*/
|
|
1883
|
-
destroyChildrensWatcher(nodeItem) {
|
|
1884
|
-
if (nodeItem?.childrens?.length) {
|
|
1885
|
-
for (let node of nodeItem?.childrens) {
|
|
1886
|
-
if (node[VNode.PARSERKEY]) {
|
|
1887
|
-
node[VNode.PARSERKEY].clearWatchers();
|
|
1888
|
-
this.destroyChildrensWatcher(node);
|
|
1889
|
-
}
|
|
1890
|
-
}
|
|
1891
|
-
}
|
|
1892
|
-
}
|
|
1893
|
-
/**
|
|
1894
|
-
* 插入自身节点
|
|
1895
|
-
*/
|
|
1896
|
-
appendNode() {
|
|
1897
|
-
if (this.parent.childrens && this.node) {
|
|
1898
|
-
this.node[VNode.PARSERKEY] = this;
|
|
1899
|
-
this.parent.childrens.push(this.node);
|
|
1900
|
-
if (this.node instanceof VNode.Element && this.ob[SCOPE_ID]) {
|
|
1901
|
-
this.node.attributes["data-scoped-" + this.ob[SCOPE_ID]] = undefined;
|
|
1902
|
-
}
|
|
1903
|
-
this.ext.render?.appendNode(this.node);
|
|
1904
|
-
this.notifyNodeWatcher("append");
|
|
1905
|
-
}
|
|
1906
|
-
}
|
|
1907
|
-
afterParser() {
|
|
1908
|
-
this.ext.nodeTransition(this.node, "enter");
|
|
1909
|
-
}
|
|
1910
|
-
/**
|
|
1911
|
-
* 通知节点观察者
|
|
1912
|
-
* @param type 通知类型
|
|
1913
|
-
*/
|
|
1914
|
-
notifyNodeWatcher(type, propertyKey) {
|
|
1915
|
-
//除非destroy 否则node 有值
|
|
1916
|
-
this.ext.notifyNodeWatcher(this.ref, this.node, type, propertyKey);
|
|
1917
|
-
}
|
|
1918
|
-
/**
|
|
1919
|
-
* 运行表达式方法,并返回运行后的值(不带观察者)
|
|
1920
|
-
* @param express 表达式 string|function
|
|
1921
|
-
* @param ob 数据源
|
|
1922
|
-
* @returns
|
|
1923
|
-
*/
|
|
1924
|
-
runExpress(express, ob) {
|
|
1925
|
-
try {
|
|
1926
|
-
return createExpress$1(express).call(ob, ob, __GLONAL_FUNTIONS__);
|
|
1927
|
-
}
|
|
1928
|
-
catch (e) {
|
|
1929
|
-
logger.error(LOGTAG$3, "运行表达式出现错误:" + express, {
|
|
1930
|
-
ob,
|
|
1931
|
-
e
|
|
1932
|
-
});
|
|
1933
|
-
}
|
|
1934
|
-
}
|
|
1935
|
-
/**
|
|
1936
|
-
* 运行表达式方法,并返回运行后的值(带观察者)
|
|
1937
|
-
* @param express 表达式 string|function
|
|
1938
|
-
* @param ob 数据源
|
|
1939
|
-
* @param updateCallBack 更新回调
|
|
1940
|
-
* @param forceCallBack 是否强制回调
|
|
1941
|
-
* @returns
|
|
1942
|
-
*/
|
|
1943
|
-
runExpressWithWatcher(express, ob, updateCallBack, forceCallBack) {
|
|
1944
|
-
let expressFunction = typeof express === "string" ? createExpress$1(express) : express;
|
|
1945
|
-
let watcher = new Watcher(() => {
|
|
1946
|
-
try {
|
|
1947
|
-
return expressFunction.call(ob, ob, __GLONAL_FUNTIONS__);
|
|
1948
|
-
}
|
|
1949
|
-
catch (e) {
|
|
1950
|
-
logger.error(LOGTAG$3, "运行表达式出现错误", {
|
|
1951
|
-
ob,
|
|
1952
|
-
e,
|
|
1953
|
-
express
|
|
1954
|
-
});
|
|
1955
|
-
throw e;
|
|
1956
|
-
}
|
|
1957
|
-
}, updateCallBack, undefined, forceCallBack);
|
|
1958
|
-
//添加 watcher 时会有防重复和空dep判断
|
|
1959
|
-
this.addWatch(watcher);
|
|
1960
|
-
return watcher.value;
|
|
1961
|
-
}
|
|
1962
|
-
/**
|
|
1963
|
-
* 添加观察者
|
|
1964
|
-
* @param watcher
|
|
1965
|
-
*/
|
|
1966
|
-
addWatch(watcher) {
|
|
1967
|
-
if (this.watchers.includes(watcher) === false) {
|
|
1968
|
-
this.watchers.push(watcher);
|
|
1969
|
-
}
|
|
1970
|
-
}
|
|
1971
|
-
/**
|
|
1972
|
-
* 清空所有观察者
|
|
1973
|
-
*/
|
|
1974
|
-
clearWatchers() {
|
|
1975
|
-
this.watchers.forEach((w) => {
|
|
1976
|
-
w.destroy();
|
|
1977
|
-
});
|
|
1978
|
-
this.watchers.length = 0;
|
|
1979
|
-
}
|
|
1980
|
-
}
|
|
1981
|
-
|
|
1982
|
-
class ParserText extends IParser {
|
|
1983
|
-
parser() {
|
|
1984
|
-
this.node = new VNode.Text(this.ast.text, this.parent);
|
|
1985
|
-
this.appendNode();
|
|
1986
|
-
}
|
|
1987
|
-
}
|
|
1988
|
-
|
|
1989
|
-
class ParserComment extends IParser {
|
|
1990
|
-
parser() {
|
|
1991
|
-
this.node = new VNode.Comment(this.ast.text, this.parent);
|
|
1992
|
-
this.appendNode();
|
|
1993
|
-
}
|
|
1994
|
-
}
|
|
1995
|
-
|
|
1996
|
-
class ParserCondition extends IParser {
|
|
1997
|
-
parser() {
|
|
1998
|
-
this.node = new VNode.Condition(this.ast.kind, this.parent);
|
|
1999
|
-
if (this.ast.kind !== "else") {
|
|
2000
|
-
if (isEmptyStr(this.ast.condition)) {
|
|
2001
|
-
logger.error("条件命令", `当前条件命令${this.ast.kind}没有判断条件,请检查`);
|
|
2002
|
-
}
|
|
2003
|
-
let conditionResult = this.runExpressWithWatcher(this.ast.condition, this.ob, (newVal) => {
|
|
2004
|
-
let value = !!newVal;
|
|
2005
|
-
if (this.node?.result !== value) {
|
|
2006
|
-
this.node.result = value;
|
|
2007
|
-
this.reloadAllCondition();
|
|
2008
|
-
}
|
|
2009
|
-
});
|
|
2010
|
-
//第一次运行完表达式,进行留值存储
|
|
2011
|
-
this.node.result = !!conditionResult;
|
|
2012
|
-
}
|
|
2013
|
-
this.appendNode();
|
|
2014
|
-
this.renderConditionChildren();
|
|
2015
|
-
}
|
|
2016
|
-
/**
|
|
2017
|
-
* 渲染子集
|
|
2018
|
-
*
|
|
2019
|
-
* @return 返回当前渲染是否有显示变更
|
|
2020
|
-
*/
|
|
2021
|
-
renderConditionChildren() {
|
|
2022
|
-
let newShowState = false;
|
|
2023
|
-
let prevResult = this.getPrevIfResult();
|
|
2024
|
-
if (prevResult) {
|
|
2025
|
-
newShowState = false;
|
|
2026
|
-
}
|
|
2027
|
-
else if (this.ast.kind === "else") {
|
|
2028
|
-
newShowState = true;
|
|
2029
|
-
}
|
|
2030
|
-
else {
|
|
2031
|
-
//刷新一次result
|
|
2032
|
-
this.node.result = !!this.runExpress(this.ast.condition, this.ob);
|
|
2033
|
-
if (this.node.result) {
|
|
2034
|
-
newShowState = true;
|
|
2035
|
-
}
|
|
2036
|
-
}
|
|
2037
|
-
//展示状态发生改变才去触发子节点的创建或销毁
|
|
2038
|
-
if (newShowState !== this.node.isShow) {
|
|
2039
|
-
this.node.isShow = newShowState;
|
|
2040
|
-
if (newShowState) {
|
|
2041
|
-
if (this.ast.childrens) {
|
|
2042
|
-
this.ext.parserNodes(this.ast.childrens, this.node, this.ob);
|
|
2043
|
-
}
|
|
2044
|
-
}
|
|
2045
|
-
else {
|
|
2046
|
-
//销毁子集,if切换时,使用keepalive
|
|
2047
|
-
this.destroyChildrens(true);
|
|
2048
|
-
}
|
|
2049
|
-
return true;
|
|
2050
|
-
}
|
|
2051
|
-
return false;
|
|
2052
|
-
}
|
|
2053
|
-
/**
|
|
2054
|
-
* 获取同级前面的判断条件结果,如果有一个true则返回true,
|
|
2055
|
-
* 否则认为上面所有条件判断都为false
|
|
2056
|
-
* @returns
|
|
2057
|
-
*/
|
|
2058
|
-
getPrevIfResult() {
|
|
2059
|
-
/**
|
|
2060
|
-
* 由于页面AST的解析及装载顺序是从上向下的
|
|
2061
|
-
* 所以,当运行到此节点时,👆面的条件已全部完成运行,并返回了结果
|
|
2062
|
-
*/
|
|
2063
|
-
//如果当前节点就是if则算上面(虚拟条件为false)
|
|
2064
|
-
if (this.ast.kind === "if") {
|
|
2065
|
-
return false;
|
|
2066
|
-
}
|
|
2067
|
-
let prevNode = this.node?.prev;
|
|
2068
|
-
//向上查询,获取级联条件结果
|
|
2069
|
-
while (prevNode && prevNode instanceof VNode.Condition) {
|
|
2070
|
-
if (prevNode.result) {
|
|
2071
|
-
return true;
|
|
2072
|
-
}
|
|
2073
|
-
//避免相邻之间互相影响
|
|
2074
|
-
if (prevNode.cmdName === "if") {
|
|
2075
|
-
break;
|
|
2076
|
-
}
|
|
2077
|
-
prevNode = prevNode.prev;
|
|
2078
|
-
}
|
|
2079
|
-
return false;
|
|
2080
|
-
}
|
|
2081
|
-
/**
|
|
2082
|
-
* 重载所有的判断(从上到下)
|
|
2083
|
-
*/
|
|
2084
|
-
reloadAllCondition() {
|
|
2085
|
-
/**
|
|
2086
|
-
* 当当前值变更后,不需要向上遍历,因为值在读取时已经挂载观察者
|
|
2087
|
-
* 观察者响应时按照先后顺序去响应
|
|
2088
|
-
* 所以当当前值变更时,之前的条件如果有变动就已经变动完毕
|
|
2089
|
-
*
|
|
2090
|
-
* 这里只需要向下去重置条件即可
|
|
2091
|
-
*/
|
|
2092
|
-
//执行自己的子集渲染
|
|
2093
|
-
let isChange = this.renderConditionChildren();
|
|
2094
|
-
/**
|
|
2095
|
-
* 如果自己发生变更,则向下传递影响性
|
|
2096
|
-
* 若自身无变更,则不向下传递,交由下面的观察者触发
|
|
2097
|
-
*
|
|
2098
|
-
* 这样可以过滤掉多条件相同观察对象的场景的无效响应
|
|
2099
|
-
*
|
|
2100
|
-
* 例如:
|
|
2101
|
-
* @if(a ===1){
|
|
2102
|
-
* }
|
|
2103
|
-
* else if(a===2){
|
|
2104
|
-
* }
|
|
2105
|
-
* else if(true){
|
|
2106
|
-
* }
|
|
2107
|
-
*
|
|
2108
|
-
* 若a从3变更到1时
|
|
2109
|
-
* 第一个if发生变更向下传递所有变更影响
|
|
2110
|
-
* 这时else if(a===2) 也收到变更通知, 这时发现自身展示状态无变更,则不向下传递影响
|
|
2111
|
-
*/
|
|
2112
|
-
if (isChange) {
|
|
2113
|
-
let next = this.node?.next;
|
|
2114
|
-
//有下一级 && 下一级是条件节点 && 下一级不是if起始
|
|
2115
|
-
while (next && next instanceof VNode.Condition && next.cmdName !== "if") {
|
|
2116
|
-
let parserTarget = next[VNode.PARSERKEY];
|
|
2117
|
-
if (parserTarget && parserTarget instanceof ParserCondition) {
|
|
2118
|
-
parserTarget.renderConditionChildren();
|
|
2119
|
-
}
|
|
2120
|
-
next = next.next;
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
}
|
|
2124
|
-
}
|
|
2125
|
-
|
|
2126
|
-
/**
|
|
2127
|
-
* For循环专用表达式运行方法
|
|
2128
|
-
*/
|
|
2129
|
-
function createExpress(letKey, keyVal, condition) {
|
|
2130
|
-
try {
|
|
2131
|
-
return new Function(EXPRESSHANDLERTAG, `${EXPRESSHANDLERTAG}.${letKey}=${keyVal}; return ${condition};`);
|
|
2132
|
-
}
|
|
2133
|
-
catch {
|
|
2134
|
-
throw new Error(`For循环命令,表达式运行依赖采集出现未知错误,其中letKey:${letKey},keyVal:${keyVal},condition:${condition}`);
|
|
2135
|
-
}
|
|
2136
|
-
}
|
|
2137
|
-
class ParserList extends IParser {
|
|
2138
|
-
parser() {
|
|
2139
|
-
this.node = new VNode.List(this.parent);
|
|
2140
|
-
this.appendNode();
|
|
2141
|
-
this.renderChildrens();
|
|
2142
|
-
}
|
|
2143
|
-
renderChildrens() {
|
|
2144
|
-
switch (this.ast.keyType) {
|
|
2145
|
-
case "condition":
|
|
2146
|
-
this.renderConditionChildrens();
|
|
2147
|
-
break;
|
|
2148
|
-
case "in":
|
|
2149
|
-
case "of":
|
|
2150
|
-
this.renderInOrOfChildrens();
|
|
2151
|
-
break;
|
|
2152
|
-
}
|
|
2153
|
-
}
|
|
2154
|
-
renderConditionChildrens() {
|
|
2155
|
-
let param = this.ast.param;
|
|
2156
|
-
let forOb = Object.create(this.ob);
|
|
2157
|
-
/**
|
|
2158
|
-
* 此处采用自定义表达式方法目的是:
|
|
2159
|
-
*
|
|
2160
|
-
* 此处存在两个依赖采集点,分别是:defaultKeyVal和condition
|
|
2161
|
-
* 这两个采集点可能存在依赖点重叠,如果重叠则会造成重复遍历
|
|
2162
|
-
* 为了解决此问题,将创建一个复合表达式,对齐进行统一采集
|
|
2163
|
-
*
|
|
2164
|
-
* 该方法会设置一次默认值,并且返回首次的判断结果
|
|
2165
|
-
*/
|
|
2166
|
-
let breakVal = !!this.runExpressWithWatcher(createExpress(param.letKey, param.defaultKeyVal, param.condition), forOb, () => {
|
|
2167
|
-
//每次都需要重新观察
|
|
2168
|
-
this.clearWatchers();
|
|
2169
|
-
this.renderChildrens();
|
|
2170
|
-
}, true);
|
|
2171
|
-
let index = 0;
|
|
2172
|
-
while (breakVal) {
|
|
2173
|
-
//每次都要创新新的对象,因为对象是引用类型,不可以公用一个对象传递
|
|
2174
|
-
//如果挂载的新属性都是作为渲染,则可以用同一个属性传递
|
|
2175
|
-
//但是我们的属性可能会存在于一些延时触发的事件中
|
|
2176
|
-
let stepOb = Object.create(this.ob);
|
|
2177
|
-
//设置数据劫持属性
|
|
2178
|
-
defineObserverProperty(stepOb, param.letKey, forOb[param.letKey]);
|
|
2179
|
-
this.renderItem(stepOb, index++);
|
|
2180
|
-
//执行下一次循环设值
|
|
2181
|
-
this.runExpress(param.step, forOb);
|
|
2182
|
-
//读取下一次的判断条件
|
|
2183
|
-
breakVal = !!this.runExpress(param.condition, forOb);
|
|
2184
|
-
}
|
|
2185
|
-
this.destroyOldChildrens(index);
|
|
2186
|
-
}
|
|
2187
|
-
renderInOrOfChildrens() {
|
|
2188
|
-
let param = this.ast.param;
|
|
2189
|
-
let listOb = this.runExpressWithWatcher(param.dataKey, this.ob, (nv, ov) => {
|
|
2190
|
-
//每次都需要重新观察
|
|
2191
|
-
this.clearWatchers();
|
|
2192
|
-
this.renderChildrens();
|
|
2193
|
-
});
|
|
2194
|
-
let index = 0;
|
|
2195
|
-
if (listOb && (Array.isArray(listOb) || isPlainObject(listOb))) {
|
|
2196
|
-
for (let key in listOb) {
|
|
2197
|
-
let stepOb = Object.create(this.ob);
|
|
2198
|
-
//对于数组时,index为索引,对于对象index为key(统称索引Key)
|
|
2199
|
-
if (param.indexKey) {
|
|
2200
|
-
defineObserverProperty(stepOb, param.indexKey, Array.isArray(listOb) ? Number(key) : key);
|
|
2201
|
-
}
|
|
2202
|
-
if (param.itemKey) {
|
|
2203
|
-
defineObserverProperty(stepOb, param.itemKey, listOb[key]);
|
|
2204
|
-
}
|
|
2205
|
-
this.renderItem(stepOb, index++);
|
|
2206
|
-
}
|
|
2207
|
-
}
|
|
2208
|
-
this.destroyOldChildrens(index);
|
|
2209
|
-
}
|
|
2210
|
-
/**
|
|
2211
|
-
* 渲染循环项
|
|
2212
|
-
* @param ob
|
|
2213
|
-
* @param index
|
|
2214
|
-
*/
|
|
2215
|
-
renderItem(ob, index) {
|
|
2216
|
-
if (!this.ast.childrens?.length) {
|
|
2217
|
-
return;
|
|
2218
|
-
}
|
|
2219
|
-
let stepList = this.node?.childrens?.[index];
|
|
2220
|
-
//若已经存在,则响应变更
|
|
2221
|
-
if (stepList) {
|
|
2222
|
-
foEachProperties(ob, (key, val) => {
|
|
2223
|
-
//@ts-ignore
|
|
2224
|
-
if (stepList.ob[key] !== val) {
|
|
2225
|
-
//新老值不一致时
|
|
2226
|
-
//设置值,做值变更通知
|
|
2227
|
-
//@ts-ignore
|
|
2228
|
-
stepList.ob[key] = val;
|
|
2229
|
-
}
|
|
2230
|
-
});
|
|
2231
|
-
}
|
|
2232
|
-
else {
|
|
2233
|
-
new ParserListeItem(this.ast, ob, this.node, this.ext);
|
|
2234
|
-
}
|
|
2235
|
-
}
|
|
2236
|
-
/**
|
|
2237
|
-
* 销毁历史遗留多余的节点
|
|
2238
|
-
* @param index
|
|
2239
|
-
*/
|
|
2240
|
-
destroyOldChildrens(index) {
|
|
2241
|
-
while (this.node.childrens.length > index) {
|
|
2242
|
-
let item = this.node.childrens.pop();
|
|
2243
|
-
if (item) {
|
|
2244
|
-
item[VNode.PARSERKEY]?.destroy(false);
|
|
2245
|
-
}
|
|
2246
|
-
else {
|
|
2247
|
-
break;
|
|
2248
|
-
}
|
|
2249
|
-
}
|
|
2250
|
-
}
|
|
2251
|
-
}
|
|
2252
|
-
class ParserListeItem extends IParser {
|
|
2253
|
-
parser() {
|
|
2254
|
-
this.node = new VNode.ListItem(this.ob, this.parent);
|
|
2255
|
-
this.appendNode();
|
|
2256
|
-
this.ast.childrens && this.ext.parserNodes(this.ast.childrens, this.node, this.ob);
|
|
2257
|
-
}
|
|
2258
|
-
}
|
|
2259
|
-
|
|
2260
|
-
class ParserCode extends IParser {
|
|
2261
|
-
parser() {
|
|
2262
|
-
if (isEmptyStr(this.ast.cmdName)) {
|
|
2263
|
-
logger.error("模板指令", "解析AST转换VNode时发生错误,未找到指令名称", this.ast);
|
|
2264
|
-
throw new Error("解析AST转换VNode时发生错误,未找到指令名称");
|
|
2265
|
-
}
|
|
2266
|
-
let express = undefined;
|
|
2267
|
-
//全局过滤器
|
|
2268
|
-
if (this.ast.cmdName === "Html" || this.ast.cmdName === "Text") {
|
|
2269
|
-
express = this.ast.param;
|
|
2270
|
-
}
|
|
2271
|
-
else if (this.ast.cmdName.startsWith(GLOBAL_TAG + ".")) {
|
|
2272
|
-
express = `${this.ast.cmdName}(${this.ast.param})`;
|
|
2273
|
-
}
|
|
2274
|
-
else if (this.ast.cmdName in this.ob && typeof this.ob[this.ast.cmdName] === "function") {
|
|
2275
|
-
express = `${createFuntionBody(this.ast.cmdName)}(${this.ast.param})`;
|
|
2276
|
-
}
|
|
2277
|
-
if (express) {
|
|
2278
|
-
let data = this.runExpressWithWatcher(express, this.ob, (newVal) => {
|
|
2279
|
-
if (this.node instanceof VNode.Html) {
|
|
2280
|
-
this.node.html = transformText(newVal);
|
|
2281
|
-
}
|
|
2282
|
-
else {
|
|
2283
|
-
this.node.text = transformText(newVal);
|
|
2284
|
-
}
|
|
2285
|
-
this.ext.render?.updateNode(this.node);
|
|
2286
|
-
//不需要做nodeChange广播, 因为它不具备ref能力
|
|
2287
|
-
});
|
|
2288
|
-
data = transformText(data);
|
|
2289
|
-
if (this.ast.cmdName === "Html") {
|
|
2290
|
-
data ||= [];
|
|
2291
|
-
this.node = new VNode.Html(data, this.parent);
|
|
2292
|
-
}
|
|
2293
|
-
else {
|
|
2294
|
-
this.node = new VNode.Text(data, this.parent);
|
|
2295
|
-
}
|
|
2296
|
-
this.appendNode();
|
|
2297
|
-
return;
|
|
2298
|
-
}
|
|
2299
|
-
throw new Error(`未找到命令:${this.ast.cmdName}`);
|
|
2300
|
-
}
|
|
2301
|
-
}
|
|
2302
|
-
function transformText(val) {
|
|
2303
|
-
if (val === undefined || val === null)
|
|
2304
|
-
return "";
|
|
2305
|
-
return val.toString();
|
|
2306
|
-
}
|
|
2307
|
-
|
|
2308
|
-
const DEFAULT_SECTION_TAG = "default";
|
|
2309
|
-
class ParserRenderSection extends IParser {
|
|
2310
|
-
parser() {
|
|
2311
|
-
let paramData = this.transformParam();
|
|
2312
|
-
this.node = new VNode.RenderSection(paramData.id, this.parent);
|
|
2313
|
-
this.node.params = paramData.params;
|
|
2314
|
-
this.node.section ??= this.ob.$sections?.[paramData.id];
|
|
2315
|
-
this.appendNode();
|
|
2316
|
-
if (this.node.section) {
|
|
2317
|
-
/**
|
|
2318
|
-
* section 挂载子组件中
|
|
2319
|
-
*
|
|
2320
|
-
* ob是父组件渲染组件时的ob,在此之上,添加一些param
|
|
2321
|
-
* 然后用当前组件的parser+新的ob去渲染
|
|
2322
|
-
*
|
|
2323
|
-
* 渲染出来的子集属于组件的子集
|
|
2324
|
-
*/
|
|
2325
|
-
if (this.node.section.params) {
|
|
2326
|
-
this.node.ob = Object.create(this.node.section.ob || this.ob);
|
|
2327
|
-
this.node.section.params?.forEach((item, index) => {
|
|
2328
|
-
defineObserverProperty(this.node.ob, item, this.node.params[index]);
|
|
2329
|
-
});
|
|
2330
|
-
}
|
|
2331
|
-
else {
|
|
2332
|
-
//无参数 不需要创建新的对象,避免性能开销
|
|
2333
|
-
this.node.ob = this.node.section.ob || this.ob;
|
|
2334
|
-
}
|
|
2335
|
-
//使用之前的node.parser去渲染
|
|
2336
|
-
(this.node.section.parser || this.ext).parserNodes(this.node.section.asts, this.node, this.node.ob);
|
|
2337
|
-
}
|
|
2338
|
-
}
|
|
2339
|
-
transformParam() {
|
|
2340
|
-
if (this.ast.param) {
|
|
2341
|
-
let expressVal = this.runExpressWithWatcher(`[${this.ast.param}]`, this.ob, (newVal) => {
|
|
2342
|
-
let newSectionId = newVal[0] || DEFAULT_SECTION_TAG;
|
|
2343
|
-
if (newSectionId !== this.node.id) {
|
|
2344
|
-
throw new Error("section id 不可动态变更");
|
|
2345
|
-
}
|
|
2346
|
-
this.node.params = newVal.slice(1);
|
|
2347
|
-
if (this.node?.ob && this.node.section) {
|
|
2348
|
-
this.node.section.params?.forEach((item, index) => {
|
|
2349
|
-
if (this.node?.ob) {
|
|
2350
|
-
if (this.node.ob[item] !== this.node.params[index]) {
|
|
2351
|
-
this.node.ob[item] = this.node.params[index];
|
|
2352
|
-
}
|
|
2353
|
-
}
|
|
2354
|
-
});
|
|
2355
|
-
}
|
|
2356
|
-
});
|
|
2357
|
-
return {
|
|
2358
|
-
id: expressVal[0] || DEFAULT_SECTION_TAG,
|
|
2359
|
-
params: expressVal.slice(1)
|
|
2360
|
-
};
|
|
2361
|
-
}
|
|
2362
|
-
else {
|
|
2363
|
-
return {
|
|
2364
|
-
id: DEFAULT_SECTION_TAG,
|
|
2365
|
-
params: []
|
|
2366
|
-
};
|
|
2367
|
-
}
|
|
2368
|
-
}
|
|
2369
|
-
}
|
|
2370
|
-
|
|
2371
|
-
const LOGTAG$2 = "组件解析";
|
|
2372
|
-
function checkIsComponent(tagName, ob) {
|
|
2373
|
-
return !!ob.components[tagName] || !!getGlobalComponent(tagName);
|
|
2374
|
-
}
|
|
2375
|
-
class ParserComponent extends IParser {
|
|
2376
|
-
parser() {
|
|
2377
|
-
//唤醒时
|
|
2378
|
-
if (this.ast.node) {
|
|
2379
|
-
this.node = this.ast.node;
|
|
2380
|
-
//重新做层级挂载
|
|
2381
|
-
this.node.parent = this.parent;
|
|
2382
|
-
//唤醒时做一次 watcher同步
|
|
2383
|
-
this.initPropData();
|
|
2384
|
-
this.appendNode();
|
|
2385
|
-
this.node.component?.$mount(this.node);
|
|
2386
|
-
return;
|
|
2387
|
-
}
|
|
2388
|
-
this.node = new VNode.Component(this.parent);
|
|
2389
|
-
this.initPropData();
|
|
2390
|
-
this.initEvent();
|
|
2391
|
-
this.appendNode();
|
|
2392
|
-
this.renderChildren();
|
|
2393
|
-
}
|
|
2394
|
-
/**
|
|
2395
|
-
* 是否允许重载
|
|
2396
|
-
* 直接指向内存的组件,无法重新实例化
|
|
2397
|
-
*/
|
|
2398
|
-
get canReload() {
|
|
2399
|
-
return "tagName" in this.ast || typeof this.ast.component === "function";
|
|
2400
|
-
}
|
|
2401
|
-
/** 用于重载 */
|
|
2402
|
-
reload() {
|
|
2403
|
-
if (this.canReload) {
|
|
2404
|
-
//无需考虑sleep,渲染时会挂载到无根节点上
|
|
2405
|
-
this.beforeDestroy();
|
|
2406
|
-
this.renderChildren();
|
|
2407
|
-
}
|
|
2408
|
-
else {
|
|
2409
|
-
logger.warn(LOGTAG$2, `当前组件无法实现reload`, this.node);
|
|
2410
|
-
}
|
|
2411
|
-
}
|
|
2412
|
-
initPropData() {
|
|
2413
|
-
for (let attr of this.ast.attributes) {
|
|
2414
|
-
if (attr.name === "ref") {
|
|
2415
|
-
if (isEmptyStr(attr.value)) {
|
|
2416
|
-
logger.warn(LOGTAG$2, "元素的ref值不可以为空");
|
|
2417
|
-
continue;
|
|
2418
|
-
}
|
|
2419
|
-
this.ref = attr.value;
|
|
2420
|
-
this.ext.addRef(attr.value, this.node);
|
|
2421
|
-
continue;
|
|
2422
|
-
}
|
|
2423
|
-
if (attr.name === "keep-alive" && attr.value !== "false") {
|
|
2424
|
-
this.node.keepalive = true;
|
|
2425
|
-
}
|
|
2426
|
-
if (attr.express) {
|
|
2427
|
-
this.node.propValues[attr.name] = this.transformPropValue(this.runExpressWithWatcher(attr.express, this.ob, (newVal) => {
|
|
2428
|
-
this.node.propValues[attr.name] = this.transformPropValue(newVal);
|
|
2429
|
-
// 不做render更新,数据变更广播会向下传递
|
|
2430
|
-
this.notifyNodeWatcher("update", attr.name);
|
|
2431
|
-
}));
|
|
2432
|
-
}
|
|
2433
|
-
else {
|
|
2434
|
-
this.node.propValues[attr.name] = attr.value;
|
|
2435
|
-
}
|
|
2436
|
-
}
|
|
2437
|
-
this.node.propValues = observer(this.node.propValues);
|
|
2438
|
-
}
|
|
2439
|
-
initEvent() {
|
|
2440
|
-
this.ast.events.forEach((event) => {
|
|
2441
|
-
let eventCallBack = event.functionName ? this.ob[event.functionName] : undefined;
|
|
2442
|
-
if (event.functionName === undefined) {
|
|
2443
|
-
this.node.events.push([
|
|
2444
|
-
event.name,
|
|
2445
|
-
{
|
|
2446
|
-
modifiers: event.modifiers,
|
|
2447
|
-
//noop 回调,为空方法做兼容,例如:@click.stop,仅做阻止冒泡
|
|
2448
|
-
callBack: noop
|
|
2449
|
-
}
|
|
2450
|
-
]);
|
|
2451
|
-
}
|
|
2452
|
-
else if (eventCallBack && typeof eventCallBack === "function") {
|
|
2453
|
-
this.node.events.push([
|
|
2454
|
-
event.name,
|
|
2455
|
-
{
|
|
2456
|
-
modifiers: event.modifiers,
|
|
2457
|
-
callBack: (e) => {
|
|
2458
|
-
let eventParams = [];
|
|
2459
|
-
if (event.functionParam) {
|
|
2460
|
-
//事件触发时,主动获取,不需要做数据劫持监听
|
|
2461
|
-
eventParams = this.runExpress(`[${event.functionParam}]`, this.ob);
|
|
2462
|
-
}
|
|
2463
|
-
eventCallBack.call(this.ext.ob, e, ...eventParams);
|
|
2464
|
-
}
|
|
2465
|
-
}
|
|
2466
|
-
]);
|
|
2467
|
-
}
|
|
2468
|
-
else {
|
|
2469
|
-
throw new Error(`${"tagName" in this.ast ? this.ast.tagName : ""}元素中${event.name}事件所指定的回调(${event.functionName})方法未找到,请检查`);
|
|
2470
|
-
}
|
|
2471
|
-
});
|
|
2472
|
-
}
|
|
2473
|
-
async renderChildren() {
|
|
2474
|
-
if ("tagName" in this.ast) {
|
|
2475
|
-
let component = this.ob.components[this.ast.tagName] || getGlobalComponent(this.ast.tagName);
|
|
2476
|
-
if (component === undefined) {
|
|
2477
|
-
logger.error(LOGTAG$2, `渲染组件失败,未找到名称为'${this.ast.tagName}'的私有组件/全局组件`);
|
|
2478
|
-
return;
|
|
2479
|
-
}
|
|
2480
|
-
if (!(JOKER_COMPONENT_TAG in component)) {
|
|
2481
|
-
component = (await component()).default;
|
|
2482
|
-
}
|
|
2483
|
-
let sections = this.getSections();
|
|
2484
|
-
this.node.name = this.ast.tagName;
|
|
2485
|
-
this.node.component = new component(this.node?.propValues, sections, this.node?.keepalive);
|
|
2486
|
-
}
|
|
2487
|
-
else if (typeof this.ast.component === "function") {
|
|
2488
|
-
let sections = this.getSections();
|
|
2489
|
-
this.node.component = new this.ast.component(this.node?.propValues, sections, this.node?.keepalive);
|
|
2490
|
-
}
|
|
2491
|
-
else {
|
|
2492
|
-
this.node.component = this.ast.component;
|
|
2493
|
-
}
|
|
2494
|
-
//如果没有name时取初始化后的name
|
|
2495
|
-
if (!this.node.name &&
|
|
2496
|
-
"name" in this.node.component &&
|
|
2497
|
-
this.node?.component.name &&
|
|
2498
|
-
typeof this.node.component.name === "string") {
|
|
2499
|
-
this.node.name = this.node?.component.name;
|
|
2500
|
-
}
|
|
2501
|
-
this.node?.component.$mount(this.node);
|
|
2502
|
-
let component = this.node?.component;
|
|
2503
|
-
if (component.isKeepAlive) {
|
|
2504
|
-
this.ast.node = this.node;
|
|
2505
|
-
}
|
|
2506
|
-
}
|
|
2507
|
-
getSections() {
|
|
2508
|
-
let result = {};
|
|
2509
|
-
let resolvedAsts = [];
|
|
2510
|
-
//剔除条件
|
|
2511
|
-
this.ast.childrens.forEach((ast) => {
|
|
2512
|
-
if (ast.type === AST.NodeType.COMMAND && ast.cmdName === "if" && ast.childrens) {
|
|
2513
|
-
let ifAst = ast;
|
|
2514
|
-
let hasSection = ast.childrens.some((n) => n.type === AST.NodeType.COMMAND && n.cmdName === "section");
|
|
2515
|
-
let validateCondition = ifAst.condition.startsWith(EXPRESSHANDLERTAG + ".$sections");
|
|
2516
|
-
//只要根符合$section判断,无论是否时default一律处理,不考虑劫持
|
|
2517
|
-
if (validateCondition) {
|
|
2518
|
-
let conditionResult = this.runExpress(ifAst.condition, this.ob);
|
|
2519
|
-
if (conditionResult) {
|
|
2520
|
-
resolvedAsts.push(...ast.childrens);
|
|
2521
|
-
return;
|
|
2522
|
-
}
|
|
2523
|
-
return;
|
|
2524
|
-
}
|
|
2525
|
-
if (hasSection && ifAst.kind === "if" && !validateCondition) {
|
|
2526
|
-
logger.warn(LOGTAG$2, "在解析section时,发现该section包裹在一个条件语句中,该条件语句仅支持以$sections进行if判断,已作排出");
|
|
2527
|
-
return;
|
|
2528
|
-
}
|
|
2529
|
-
}
|
|
2530
|
-
resolvedAsts.push(ast);
|
|
2531
|
-
});
|
|
2532
|
-
resolvedAsts.forEach((ast) => {
|
|
2533
|
-
if (ast.type === AST.NodeType.COMMAND && ast.cmdName === "section") {
|
|
2534
|
-
let sectionAst = ast;
|
|
2535
|
-
let id = sectionAst.id || DEFAULT_SECTION_TAG;
|
|
2536
|
-
if (/^(\'|\")(.*?)((\'|\"))$/.test(id)) {
|
|
2537
|
-
id = id.slice(1, -1);
|
|
2538
|
-
}
|
|
2539
|
-
//做插槽ASTS合并
|
|
2540
|
-
result[id] = result[id] || {
|
|
2541
|
-
asts: [],
|
|
2542
|
-
ob: this.ob,
|
|
2543
|
-
params: sectionAst.paramKeys,
|
|
2544
|
-
parser: this.ext
|
|
2545
|
-
};
|
|
2546
|
-
result[id].asts.push(...(ast.childrens || []));
|
|
2547
|
-
}
|
|
2548
|
-
else {
|
|
2549
|
-
result[DEFAULT_SECTION_TAG] = result[DEFAULT_SECTION_TAG] || {
|
|
2550
|
-
asts: [],
|
|
2551
|
-
ob: this.ob,
|
|
2552
|
-
parser: this.ext
|
|
2553
|
-
};
|
|
2554
|
-
result[DEFAULT_SECTION_TAG].asts.push(ast);
|
|
2555
|
-
}
|
|
2556
|
-
});
|
|
2557
|
-
return result;
|
|
2558
|
-
}
|
|
2559
|
-
beforeDestroy(keepalive) {
|
|
2560
|
-
if (keepalive === true && this.node?.component?.isKeepAlive) {
|
|
2561
|
-
this.node?.component?.$destroy();
|
|
2562
|
-
}
|
|
2563
|
-
else {
|
|
2564
|
-
this.node?.component?.$destroy(true);
|
|
2565
|
-
this.ast.node = undefined;
|
|
2566
|
-
}
|
|
2567
|
-
}
|
|
2568
|
-
transformPropValue(val) {
|
|
2569
|
-
if (typeof val === "function" && !(JOKER_COMPONENT_TAG in val)) {
|
|
2570
|
-
return val.bind(this.ext.ob);
|
|
2571
|
-
}
|
|
2572
|
-
return val;
|
|
2573
|
-
}
|
|
2574
|
-
}
|
|
2575
|
-
|
|
2576
|
-
const LOGTAG$1 = "Element解析";
|
|
2577
|
-
class ParserElement extends IParser {
|
|
2578
|
-
parser() {
|
|
2579
|
-
this.node = new VNode.Element(this.ast.tagName, this.parent);
|
|
2580
|
-
this.initAttributes();
|
|
2581
|
-
this.initEvents();
|
|
2582
|
-
this.appendNode();
|
|
2583
|
-
this.ext.parserNodes(this.ast.childrens, this.node, this.ob);
|
|
2584
|
-
}
|
|
2585
|
-
initAttributes() {
|
|
2586
|
-
for (let attr of this.ast.attributes) {
|
|
2587
|
-
if (attr.name === "ref") {
|
|
2588
|
-
if (isEmptyStr(attr.value)) {
|
|
2589
|
-
logger.warn(LOGTAG$1, "元素的ref值不可以为空");
|
|
2590
|
-
continue;
|
|
2591
|
-
}
|
|
2592
|
-
this.ref = attr.value;
|
|
2593
|
-
this.ext.addRef(attr.value, this.node);
|
|
2594
|
-
continue;
|
|
2595
|
-
}
|
|
2596
|
-
if (attr.express) {
|
|
2597
|
-
let watcherVal = this.runExpressWithWatcher(attr.express, this.ob, (newVal) => {
|
|
2598
|
-
this.node.attributes[attr.name] = this.transformAttrVal(newVal);
|
|
2599
|
-
//通知渲染更新
|
|
2600
|
-
this.ext.render?.updateNode(this.node, attr.name);
|
|
2601
|
-
this.notifyNodeWatcher("update", attr.name);
|
|
2602
|
-
});
|
|
2603
|
-
this.node.attributes[attr.name] = this.transformAttrVal(watcherVal);
|
|
2604
|
-
}
|
|
2605
|
-
else {
|
|
2606
|
-
this.node.attributes[attr.name] = attr.value;
|
|
2607
|
-
}
|
|
2608
|
-
}
|
|
2609
|
-
}
|
|
2610
|
-
initEvents() {
|
|
2611
|
-
for (let event of this.ast.events) {
|
|
2612
|
-
let eventCallBack = event.functionName ? this.ob[event.functionName] : undefined;
|
|
2613
|
-
if (event.functionName === undefined || (eventCallBack && typeof eventCallBack === "function")) {
|
|
2614
|
-
this.node?.events.push([
|
|
2615
|
-
event.name,
|
|
2616
|
-
{
|
|
2617
|
-
modifiers: event.modifiers,
|
|
2618
|
-
callBack: (e) => {
|
|
2619
|
-
//如果空方法,不做异常处理,为事件挡板做兼容,例如:@keydown.stop
|
|
2620
|
-
if (eventCallBack === undefined) {
|
|
2621
|
-
return;
|
|
2622
|
-
}
|
|
2623
|
-
let eventParams = [];
|
|
2624
|
-
if (event.functionParam) {
|
|
2625
|
-
//事件触发时,主动获取,不需要做数据劫持监听
|
|
2626
|
-
eventParams = this.runExpress(`[${event.functionParam}]`, this.ob);
|
|
2627
|
-
}
|
|
2628
|
-
if (eventCallBack) {
|
|
2629
|
-
eventCallBack.call(this.ext.ob, e, ...eventParams);
|
|
2630
|
-
}
|
|
2631
|
-
}
|
|
2632
|
-
}
|
|
2633
|
-
]);
|
|
2634
|
-
}
|
|
2635
|
-
else {
|
|
2636
|
-
throw new Error(`${this.ast.tagName}元素中${event.name}事件所指定的回调(${event.functionName})方法未找到,请检查`);
|
|
2637
|
-
}
|
|
2638
|
-
}
|
|
2639
|
-
}
|
|
2640
|
-
transformAttrVal(val) {
|
|
2641
|
-
if (val === undefined) {
|
|
2642
|
-
return false;
|
|
2643
|
-
}
|
|
2644
|
-
if (typeof val === "string") {
|
|
2645
|
-
return val;
|
|
2646
|
-
}
|
|
2647
|
-
if (typeof val === "boolean") {
|
|
2648
|
-
return val;
|
|
2649
|
-
}
|
|
2650
|
-
return val;
|
|
2651
|
-
}
|
|
2652
|
-
}
|
|
2653
|
-
|
|
2654
|
-
class ParserTemplate {
|
|
2655
|
-
asts;
|
|
2656
|
-
ob;
|
|
2657
|
-
/** VNode 根 */
|
|
2658
|
-
root = new VNode.Root();
|
|
2659
|
-
/** VNode ref索引集 */
|
|
2660
|
-
refs = {};
|
|
2661
|
-
sleeped = false;
|
|
2662
|
-
/**
|
|
2663
|
-
* node变更观察者
|
|
2664
|
-
*/
|
|
2665
|
-
nodeWatcherEvents = {};
|
|
2666
|
-
/** VNode 渲染处理程序 (依赖注入) */
|
|
2667
|
-
render;
|
|
2668
|
-
constructor(asts, ob, parent) {
|
|
2669
|
-
this.asts = asts;
|
|
2670
|
-
this.ob = ob;
|
|
2671
|
-
this.root.component = ob;
|
|
2672
|
-
this.render = IContainer.get(Render.IRENDERIOCTAGID) ?? new Render.DomRender();
|
|
2673
|
-
if (parent && parent instanceof VNode.Node) {
|
|
2674
|
-
this.root.parent = parent;
|
|
2675
|
-
parent.childrens ??= [];
|
|
2676
|
-
parent.childrens.push(this.root);
|
|
2677
|
-
}
|
|
2678
|
-
}
|
|
2679
|
-
parser() {
|
|
2680
|
-
this.parserNodes(this.asts, this.root);
|
|
2681
|
-
}
|
|
2682
|
-
/**
|
|
2683
|
-
* VNode挂载
|
|
2684
|
-
* @param root
|
|
2685
|
-
*/
|
|
2686
|
-
mount(root) {
|
|
2687
|
-
//如果已经输出,则直接做挂载到render.elements
|
|
2688
|
-
if (this.sleeped) {
|
|
2689
|
-
this.weakup();
|
|
2690
|
-
}
|
|
2691
|
-
this.render?.mount(root);
|
|
2692
|
-
}
|
|
2693
|
-
/**
|
|
2694
|
-
* 编译AST子集
|
|
2695
|
-
* @param asts
|
|
2696
|
-
* @param parent
|
|
2697
|
-
*/
|
|
2698
|
-
parserNodes(asts, parent, ob) {
|
|
2699
|
-
asts.forEach((ast) => {
|
|
2700
|
-
if (ast.type === AST.NodeType.TEXT) {
|
|
2701
|
-
new ParserText(ast, ob ?? this.ob, parent, this);
|
|
2702
|
-
}
|
|
2703
|
-
else if (ast.type === AST.NodeType.COMMENT) {
|
|
2704
|
-
new ParserComment(ast, ob ?? this.ob, parent, this);
|
|
2705
|
-
}
|
|
2706
|
-
else if (ast.type === AST.NodeType.COMPONENT) {
|
|
2707
|
-
//动态组件
|
|
2708
|
-
new ParserComponent(ast, ob ?? this.ob, parent, this);
|
|
2709
|
-
}
|
|
2710
|
-
else if (ast.type === AST.NodeType.ELEMENT) {
|
|
2711
|
-
let elementAST = ast;
|
|
2712
|
-
if (checkIsComponent(elementAST.tagName, ob ?? this.ob)) {
|
|
2713
|
-
new ParserComponent(elementAST, ob ?? this.ob, parent, this);
|
|
2714
|
-
}
|
|
2715
|
-
else {
|
|
2716
|
-
new ParserElement(elementAST, ob ?? this.ob, parent, this);
|
|
2717
|
-
}
|
|
2718
|
-
}
|
|
2719
|
-
else if (ast.type === AST.NodeType.COMMAND) {
|
|
2720
|
-
let cmdAST = ast;
|
|
2721
|
-
switch (cmdAST.cmdName) {
|
|
2722
|
-
case "if":
|
|
2723
|
-
case "elseif":
|
|
2724
|
-
case "else":
|
|
2725
|
-
new ParserCondition(cmdAST, ob ?? this.ob, parent, this);
|
|
2726
|
-
break;
|
|
2727
|
-
case "for":
|
|
2728
|
-
new ParserList(cmdAST, ob ?? this.ob, parent, this);
|
|
2729
|
-
break;
|
|
2730
|
-
case "RenderSection":
|
|
2731
|
-
new ParserRenderSection(cmdAST, ob ?? this.ob, parent, this);
|
|
2732
|
-
break;
|
|
2733
|
-
case "section":
|
|
2734
|
-
//区域不做任何解析,直到组件加载时,去即时处理
|
|
2735
|
-
break;
|
|
2736
|
-
default:
|
|
2737
|
-
new ParserCode(cmdAST, ob ?? this.ob, parent, this);
|
|
2738
|
-
break;
|
|
2739
|
-
}
|
|
2740
|
-
}
|
|
2741
|
-
});
|
|
2742
|
-
}
|
|
2743
|
-
/**
|
|
2744
|
-
* 添加ref
|
|
2745
|
-
* @param refName ref值
|
|
2746
|
-
* @param node VNode节点
|
|
2747
|
-
*/
|
|
2748
|
-
addRef(refKey, node) {
|
|
2749
|
-
this.refs[refKey] = this.refs[refKey] || [];
|
|
2750
|
-
this.refs[refKey].push(node);
|
|
2751
|
-
}
|
|
2752
|
-
/**
|
|
2753
|
-
* 移除Node所在ref
|
|
2754
|
-
* @param node VNode节点
|
|
2755
|
-
*/
|
|
2756
|
-
removeRef(node) {
|
|
2757
|
-
for (let refKey in this.refs) {
|
|
2758
|
-
if (this.refs[refKey].includes(node)) {
|
|
2759
|
-
remove(this.refs[refKey], node);
|
|
2760
|
-
}
|
|
2761
|
-
}
|
|
2762
|
-
}
|
|
2763
|
-
/**
|
|
2764
|
-
* 添加节点变更观察者
|
|
2765
|
-
* @param ref
|
|
2766
|
-
* @param callBack
|
|
2767
|
-
*/
|
|
2768
|
-
addNodeWatcher(ref, callBack) {
|
|
2769
|
-
this.nodeWatcherEvents[ref] = this.nodeWatcherEvents[ref] || [];
|
|
2770
|
-
this.nodeWatcherEvents[ref].push(callBack);
|
|
2771
|
-
}
|
|
2772
|
-
/**
|
|
2773
|
-
* 移除节点变更观察者
|
|
2774
|
-
* @param ref
|
|
2775
|
-
* @param callBack
|
|
2776
|
-
*/
|
|
2777
|
-
removeNodeWatcher(ref, callBack) {
|
|
2778
|
-
remove(this.nodeWatcherEvents[ref] || [], callBack);
|
|
2779
|
-
}
|
|
2780
|
-
/**
|
|
2781
|
-
* 响应节点变更,通知观察者
|
|
2782
|
-
* @param ref
|
|
2783
|
-
* @param node
|
|
2784
|
-
* @param nodeChangeType
|
|
2785
|
-
*/
|
|
2786
|
-
notifyNodeWatcher(ref, node, nodeChangeType, propertyKey) {
|
|
2787
|
-
this.nodeWatcherEvents[ref]?.forEach((callBack) => {
|
|
2788
|
-
callBack(node, nodeChangeType, propertyKey);
|
|
2789
|
-
});
|
|
2790
|
-
}
|
|
2791
|
-
sleep(node) {
|
|
2792
|
-
let parent = node || this.root;
|
|
2793
|
-
//应该所有节点remove,避免再次唤醒时,由于数据变更问题,造成dom树还原不一致/不更新
|
|
2794
|
-
parent.childrens?.forEach((m) => {
|
|
2795
|
-
let next = () => {
|
|
2796
|
-
if (m.childrens) {
|
|
2797
|
-
this.sleep(m);
|
|
2798
|
-
}
|
|
2799
|
-
m.sleep = true;
|
|
2800
|
-
this.render?.removeNode(m, true);
|
|
2801
|
-
};
|
|
2802
|
-
if (this.nodeTransition(m, "leave", undefined, () => {
|
|
2803
|
-
next();
|
|
2804
|
-
})) {
|
|
2805
|
-
return;
|
|
2806
|
-
}
|
|
2807
|
-
next();
|
|
2808
|
-
});
|
|
2809
|
-
node === undefined && (this.sleeped = true);
|
|
2810
|
-
}
|
|
2811
|
-
weakup(node) {
|
|
2812
|
-
let parent = node || this.root;
|
|
2813
|
-
parent.childrens?.forEach((m) => {
|
|
2814
|
-
m.sleep = false;
|
|
2815
|
-
this.render?.appendNode(m);
|
|
2816
|
-
if (m.childrens) {
|
|
2817
|
-
this.weakup(m);
|
|
2818
|
-
}
|
|
2819
|
-
this.nodeTransition(m, "enter");
|
|
2820
|
-
});
|
|
2821
|
-
node === undefined && (this.sleeped = false);
|
|
2822
|
-
}
|
|
2823
|
-
/**
|
|
2824
|
-
* 销毁
|
|
2825
|
-
*/
|
|
2826
|
-
destroy(keepalive) {
|
|
2827
|
-
while (this.root.childrens.length) {
|
|
2828
|
-
let item = this.root.childrens[0];
|
|
2829
|
-
if (item[VNode.PARSERKEY]) {
|
|
2830
|
-
item[VNode.PARSERKEY].destroy(keepalive);
|
|
2831
|
-
}
|
|
2832
|
-
else {
|
|
2833
|
-
//root 类型
|
|
2834
|
-
remove(this.root.childrens, item);
|
|
2835
|
-
}
|
|
2836
|
-
}
|
|
2837
|
-
this.render.destroy();
|
|
2838
|
-
this.refs = {};
|
|
2839
|
-
this.root.childrens.length = 0;
|
|
2840
|
-
this.nodeWatcherEvents = {};
|
|
2841
|
-
this.asts.length = 0;
|
|
2842
|
-
}
|
|
2843
|
-
reSetAsts(asts, keepalive) {
|
|
2844
|
-
//销毁历史产物
|
|
2845
|
-
this.destroy(keepalive);
|
|
2846
|
-
this.render = IContainer.get(Render.IRENDERIOCTAGID) ?? new Render.DomRender();
|
|
2847
|
-
this.asts = asts;
|
|
2848
|
-
}
|
|
2849
|
-
nodeTransition(node, mode, name, callBack, type) {
|
|
2850
|
-
if (node && node.parent?.childrens && (node instanceof VNode.Element || node instanceof VNode.Component)) {
|
|
2851
|
-
let nodeTransitionOption = getNodeSupportTransition(node);
|
|
2852
|
-
name ??= nodeTransitionOption?.name;
|
|
2853
|
-
type ??= nodeTransitionOption?.type;
|
|
2854
|
-
if (!name)
|
|
2855
|
-
return false;
|
|
2856
|
-
let firstElement = getFirstElement(node);
|
|
2857
|
-
if (firstElement) {
|
|
2858
|
-
mode === "enter"
|
|
2859
|
-
? this.render.elementToEnter(firstElement, name, type, () => {
|
|
2860
|
-
let parser = node[VNode.PARSERKEY];
|
|
2861
|
-
if (parser && parser.ref) {
|
|
2862
|
-
this.notifyNodeWatcher(parser.ref, node, "after-enter");
|
|
2863
|
-
}
|
|
2864
|
-
callBack?.();
|
|
2865
|
-
})
|
|
2866
|
-
: this.render.elementToLeave(firstElement, name, type, () => {
|
|
2867
|
-
let parser = node[VNode.PARSERKEY];
|
|
2868
|
-
if (parser && parser.ref) {
|
|
2869
|
-
this.notifyNodeWatcher(parser.ref, node, "after-leave");
|
|
2870
|
-
}
|
|
2871
|
-
callBack?.();
|
|
2872
|
-
});
|
|
2873
|
-
return true;
|
|
2874
|
-
}
|
|
2875
|
-
else {
|
|
2876
|
-
logger.warn("渲染核心", "在执行node动画时,发现数据不完备,请检查");
|
|
2877
|
-
}
|
|
2878
|
-
}
|
|
2879
|
-
return false;
|
|
2880
|
-
}
|
|
2881
|
-
}
|
|
2882
|
-
function getFirstElement(node) {
|
|
2883
|
-
if (node instanceof VNode.Element)
|
|
2884
|
-
return node;
|
|
2885
|
-
if (node.childrens && node.childrens.length) {
|
|
2886
|
-
for (let children of node.childrens) {
|
|
2887
|
-
if (children instanceof VNode.Element) {
|
|
2888
|
-
return children;
|
|
2889
|
-
}
|
|
2890
|
-
else {
|
|
2891
|
-
return getFirstElement(children);
|
|
2892
|
-
}
|
|
2893
|
-
}
|
|
2894
|
-
}
|
|
2895
|
-
return;
|
|
2896
|
-
}
|
|
2897
|
-
function getNodeSupportTransition(node) {
|
|
2898
|
-
if (node instanceof VNode.Element || node instanceof VNode.Component) {
|
|
2899
|
-
let attrs = node instanceof VNode.Element ? node.attributes : node.propValues;
|
|
2900
|
-
return {
|
|
2901
|
-
name: attrs["transition-name"],
|
|
2902
|
-
type: attrs["transition-type"]
|
|
2903
|
-
};
|
|
2904
|
-
}
|
|
2905
|
-
}
|
|
2906
|
-
|
|
2907
|
-
function checkPropType(key, value, types) {
|
|
2908
|
-
//undefined 不做约束
|
|
2909
|
-
if (value === undefined) {
|
|
2910
|
-
return;
|
|
2911
|
-
}
|
|
2912
|
-
let checkTypes = Array.isArray(types) ? types : [types];
|
|
2913
|
-
for (let checkType of checkTypes) {
|
|
2914
|
-
//解决proxy<Array> 场景下的类型判断异常问题
|
|
2915
|
-
if (checkType === Array && value instanceof Array) {
|
|
2916
|
-
return value;
|
|
2917
|
-
}
|
|
2918
|
-
if (typeof value === checkType.name.toLocaleLowerCase()) {
|
|
2919
|
-
return value;
|
|
2920
|
-
}
|
|
2921
|
-
}
|
|
2922
|
-
//使用第一个类型兼容转换
|
|
2923
|
-
switch (checkTypes[0]) {
|
|
2924
|
-
case Number:
|
|
2925
|
-
let newVal = Number(value);
|
|
2926
|
-
if (isNaN(newVal) === false) {
|
|
2927
|
-
return newVal;
|
|
2928
|
-
}
|
|
2929
|
-
break;
|
|
2930
|
-
case String:
|
|
2931
|
-
return String(value);
|
|
2932
|
-
}
|
|
2933
|
-
throw new Error(`props中${key.toString()}的类型不符合约束类型`);
|
|
2934
|
-
}
|
|
2935
|
-
function getPropValue(propsData, key, propsType) {
|
|
2936
|
-
let patchKey;
|
|
2937
|
-
if (typeof key !== "symbol") {
|
|
2938
|
-
patchKey = toLowerCase(key);
|
|
2939
|
-
}
|
|
2940
|
-
let propValue;
|
|
2941
|
-
if (key in propsData) {
|
|
2942
|
-
propValue = propsData[key];
|
|
2943
|
-
}
|
|
2944
|
-
else if (patchKey) {
|
|
2945
|
-
propValue = propsData[patchKey];
|
|
2946
|
-
}
|
|
2947
|
-
let propOption;
|
|
2948
|
-
if (propsType) {
|
|
2949
|
-
if (key in propsType) {
|
|
2950
|
-
propOption = propsType[key];
|
|
2951
|
-
}
|
|
2952
|
-
else if (patchKey && patchKey in propsType) {
|
|
2953
|
-
propOption = propsType[patchKey];
|
|
2954
|
-
}
|
|
2955
|
-
}
|
|
2956
|
-
if (propOption !== undefined) {
|
|
2957
|
-
if (isPlainObject(propOption) &&
|
|
2958
|
-
("type" in propOption || "required" in propOption || "default" in propOption || "validate" in propOption)) {
|
|
2959
|
-
let fullModel = propOption;
|
|
2960
|
-
if (fullModel.required && propValue === undefined) {
|
|
2961
|
-
throw new Error(`props中key:${key.toString()}是必须项,请检查`);
|
|
2962
|
-
}
|
|
2963
|
-
if (fullModel.type) {
|
|
2964
|
-
propValue = checkPropType(key, propValue, fullModel.type);
|
|
2965
|
-
}
|
|
2966
|
-
if (fullModel.validate && fullModel.validate(propValue) === false) {
|
|
2967
|
-
throw new Error(`props中key${key.toString()}的值校验错误`);
|
|
2968
|
-
}
|
|
2969
|
-
propValue = propValue ?? fullModel.default;
|
|
2970
|
-
}
|
|
2971
|
-
else if (isPropsType(propOption)) {
|
|
2972
|
-
propValue = checkPropType(key, propValue, propOption);
|
|
2973
|
-
}
|
|
2974
|
-
else {
|
|
2975
|
-
//默认值
|
|
2976
|
-
propValue = propValue ?? propOption;
|
|
2977
|
-
}
|
|
2978
|
-
return propValue;
|
|
2979
|
-
}
|
|
2980
|
-
return propValue;
|
|
2981
|
-
}
|
|
2982
|
-
function isPropsType(propOption) {
|
|
2983
|
-
if ([String, Array, Number, Object, Function, Boolean].includes(propOption)) {
|
|
2984
|
-
return true;
|
|
2985
|
-
}
|
|
2986
|
-
if (propOption instanceof Array) {
|
|
2987
|
-
return isPropsType(propOption[0]);
|
|
2988
|
-
}
|
|
2989
|
-
return false;
|
|
2990
|
-
}
|
|
2991
|
-
|
|
2992
|
-
const LOGTAG = "组件";
|
|
2993
|
-
const PROPS_DATA_KEY = Symbol.for("JOKER_PROPS_DATA_KEY");
|
|
2994
|
-
const PROPS_DATA_PROXY = Symbol.for("JOKER_PROPS_DATA_PROXY");
|
|
2995
|
-
const PRIVATE_WATCHERS = Symbol.for("JOKER_PRIVATE_WATCHERS");
|
|
2996
|
-
const EVENT_DATA_KEY = Symbol.for("JOKER_EVENT_DATA_KEY");
|
|
2997
|
-
const PARSER_TEMPLATE_TARGET = Symbol.for("JOKER_PARSER_TEMPLATE_TARGET");
|
|
2998
|
-
const SCOPE_ID = Symbol.for("JOKER_SCOPE_ID");
|
|
2999
|
-
const JOKER_COMPONENT_TAG = Symbol.for("JOKER_COMPONENT_TAG");
|
|
3000
|
-
/**
|
|
3001
|
-
* Joker组件
|
|
3002
|
-
*/
|
|
3003
|
-
class Component {
|
|
3004
|
-
$sections;
|
|
3005
|
-
isKeepAlive;
|
|
3006
|
-
static [JOKER_COMPONENT_TAG] = true;
|
|
3007
|
-
/**
|
|
3008
|
-
* scopeId 配合css:Scoped
|
|
3009
|
-
*/
|
|
3010
|
-
[SCOPE_ID];
|
|
3011
|
-
/**
|
|
3012
|
-
* 可观察数据(具备劫持观察能力)
|
|
3013
|
-
*/
|
|
3014
|
-
model = {};
|
|
3015
|
-
/**
|
|
3016
|
-
* 渲染模板
|
|
3017
|
-
*/
|
|
3018
|
-
template;
|
|
3019
|
-
/**
|
|
3020
|
-
* 挂载根
|
|
3021
|
-
*/
|
|
3022
|
-
$root;
|
|
3023
|
-
/**
|
|
3024
|
-
* 是否已睡眠
|
|
3025
|
-
*/
|
|
3026
|
-
isSleeped = false;
|
|
3027
|
-
/**
|
|
3028
|
-
* 可用的声明组件
|
|
3029
|
-
*/
|
|
3030
|
-
components = {};
|
|
3031
|
-
/**
|
|
3032
|
-
* props辅助约束
|
|
3033
|
-
* @example { name:"默认值",age:Number }
|
|
3034
|
-
* 可以配置默认值,也可以配置为约束,类型参考PropType
|
|
3035
|
-
*/
|
|
3036
|
-
propsOption;
|
|
3037
|
-
[PROPS_DATA_KEY] = {};
|
|
3038
|
-
[PARSER_TEMPLATE_TARGET];
|
|
3039
|
-
[PROPS_DATA_PROXY];
|
|
3040
|
-
[PRIVATE_WATCHERS] = [];
|
|
3041
|
-
[EVENT_DATA_KEY] = new Map();
|
|
3042
|
-
/**
|
|
3043
|
-
* @param propData prop参数
|
|
3044
|
-
* @param sections 渲染部分区域
|
|
3045
|
-
* @param isKeepAlive 是否要保持存活,启用时再destroy时只会销毁UI部分,不会销毁数据,直到使用destroy(true)才会销毁
|
|
3046
|
-
*/
|
|
3047
|
-
constructor(propData, $sections = {}, isKeepAlive) {
|
|
3048
|
-
this.$sections = $sections;
|
|
3049
|
-
this.isKeepAlive = isKeepAlive;
|
|
3050
|
-
this[PROPS_DATA_KEY] = propData || {};
|
|
3051
|
-
}
|
|
3052
|
-
/**
|
|
3053
|
-
* 主动声明接受的参数
|
|
3054
|
-
* @returns
|
|
3055
|
-
*/
|
|
3056
|
-
get props() {
|
|
3057
|
-
if (this[PROPS_DATA_PROXY] === undefined) {
|
|
3058
|
-
let self = this;
|
|
3059
|
-
this[PROPS_DATA_PROXY] = new Proxy(self[PROPS_DATA_KEY], {
|
|
3060
|
-
get(target, p) {
|
|
3061
|
-
return getPropValue(self[PROPS_DATA_KEY], p, self.propsOption);
|
|
3062
|
-
},
|
|
3063
|
-
set() {
|
|
3064
|
-
throw new Error("props 参数不允许变更,只允许单向数据传递");
|
|
3065
|
-
}
|
|
3066
|
-
});
|
|
3067
|
-
}
|
|
3068
|
-
return this[PROPS_DATA_PROXY];
|
|
3069
|
-
}
|
|
3070
|
-
/**
|
|
3071
|
-
* 挂载
|
|
3072
|
-
* @param root
|
|
3073
|
-
*/
|
|
3074
|
-
$mount(root) {
|
|
3075
|
-
this.$root = root;
|
|
3076
|
-
//从睡眠中醒来
|
|
3077
|
-
if (this.isKeepAlive && this.isSleeped) {
|
|
3078
|
-
this.isSleeped = false;
|
|
3079
|
-
if (this[PARSER_TEMPLATE_TARGET] && this.$root) {
|
|
3080
|
-
this[PARSER_TEMPLATE_TARGET].mount(this.$root);
|
|
3081
|
-
}
|
|
3082
|
-
else {
|
|
3083
|
-
logger.error(LOGTAG, `当前组件在唤醒时,发现渲染处理程序已被销毁,无法进行唤醒操作`, [
|
|
3084
|
-
this,
|
|
3085
|
-
this.$root
|
|
3086
|
-
]);
|
|
3087
|
-
return this;
|
|
3088
|
-
}
|
|
3089
|
-
this.wakeup();
|
|
3090
|
-
this.$trigger("wakeup");
|
|
3091
|
-
this.$rootVNode && weakupNotify(this.$rootVNode);
|
|
3092
|
-
return this;
|
|
3093
|
-
}
|
|
3094
|
-
this.isSleeped = false;
|
|
3095
|
-
this.model = observer(this.model);
|
|
3096
|
-
this.created();
|
|
3097
|
-
this.$trigger("created");
|
|
3098
|
-
//有模板则执行render,否则不处理
|
|
3099
|
-
this.template && this.$render();
|
|
3100
|
-
this.mounted();
|
|
3101
|
-
this.$trigger("mounted");
|
|
3102
|
-
return this;
|
|
3103
|
-
}
|
|
3104
|
-
/**
|
|
3105
|
-
* 节点动画,仅支持 element及组件节点
|
|
3106
|
-
*/
|
|
3107
|
-
$nodeTransition(nodeOrRef, mode, name, callBack, type) {
|
|
3108
|
-
if (typeof nodeOrRef === "string") {
|
|
3109
|
-
let vnode = this.$getRef(nodeOrRef);
|
|
3110
|
-
if (vnode) {
|
|
3111
|
-
nodeOrRef = vnode;
|
|
3112
|
-
}
|
|
3113
|
-
else {
|
|
3114
|
-
logger.error(LOGTAG, `执行节点动画是找不到ref=${nodeOrRef}的节点`);
|
|
3115
|
-
return;
|
|
3116
|
-
}
|
|
3117
|
-
}
|
|
3118
|
-
this[PARSER_TEMPLATE_TARGET]?.nodeTransition(nodeOrRef, mode, name, callBack, type);
|
|
3119
|
-
}
|
|
3120
|
-
/**
|
|
3121
|
-
* 销毁
|
|
3122
|
-
*/
|
|
3123
|
-
$destroy(force) {
|
|
3124
|
-
if (!force && this.isKeepAlive) {
|
|
3125
|
-
this[PARSER_TEMPLATE_TARGET]?.sleep();
|
|
3126
|
-
this.isSleeped = true;
|
|
3127
|
-
this.sleeped();
|
|
3128
|
-
this.$trigger("sleeped");
|
|
3129
|
-
this.$rootVNode && sleepNotify(this.$rootVNode);
|
|
3130
|
-
return;
|
|
3131
|
-
}
|
|
3132
|
-
this.beforeDestroy();
|
|
3133
|
-
this.$trigger("beforeDestroy");
|
|
3134
|
-
for (let watcher of this[PRIVATE_WATCHERS]) {
|
|
3135
|
-
watcher.destroy();
|
|
3136
|
-
}
|
|
3137
|
-
this[PRIVATE_WATCHERS].length = 0;
|
|
3138
|
-
this[PARSER_TEMPLATE_TARGET]?.destroy();
|
|
3139
|
-
this[PARSER_TEMPLATE_TARGET] = undefined;
|
|
3140
|
-
if (this.template && Array.isArray(this.template)) {
|
|
3141
|
-
this.template.length = 0;
|
|
3142
|
-
}
|
|
3143
|
-
this.$trigger("destroy");
|
|
3144
|
-
this[EVENT_DATA_KEY].clear();
|
|
3145
|
-
this.$root = undefined;
|
|
3146
|
-
this.isSleeped = false;
|
|
3147
|
-
this.model = {};
|
|
3148
|
-
this.$sections = {};
|
|
3149
|
-
this[PROPS_DATA_PROXY] = undefined;
|
|
3150
|
-
this[PROPS_DATA_KEY] = {};
|
|
3151
|
-
this.destroyed();
|
|
3152
|
-
}
|
|
3153
|
-
/**
|
|
3154
|
-
* VNode ref索引集
|
|
3155
|
-
*/
|
|
3156
|
-
get $refs() {
|
|
3157
|
-
return this[PARSER_TEMPLATE_TARGET]?.refs || {};
|
|
3158
|
-
}
|
|
3159
|
-
/**
|
|
3160
|
-
* 根据ref获取单个VNode
|
|
3161
|
-
*/
|
|
3162
|
-
$getRef(ref) {
|
|
3163
|
-
return this.$refs[ref]?.[0];
|
|
3164
|
-
}
|
|
3165
|
-
/**
|
|
3166
|
-
* 获取相同ref的VNode集合
|
|
3167
|
-
*/
|
|
3168
|
-
$getRefs(ref) {
|
|
3169
|
-
return this.$refs[ref];
|
|
3170
|
-
}
|
|
3171
|
-
$syncProp(propKey, modelKey, convertVal) {
|
|
3172
|
-
if (typeof modelKey === "function") {
|
|
3173
|
-
convertVal = modelKey;
|
|
3174
|
-
modelKey = undefined;
|
|
3175
|
-
}
|
|
3176
|
-
modelKey ??= propKey;
|
|
3177
|
-
convertVal ??= (val) => {
|
|
3178
|
-
return val;
|
|
3179
|
-
};
|
|
3180
|
-
//先做一次同步再去观察
|
|
3181
|
-
this.model[modelKey] = convertVal(this.props[propKey]);
|
|
3182
|
-
this.$watch(() => this.props[propKey], () => {
|
|
3183
|
-
this.model[modelKey] = convertVal?.(this.props[propKey]);
|
|
3184
|
-
});
|
|
3185
|
-
}
|
|
3186
|
-
/**
|
|
3187
|
-
* 根节点(虚拟DOM)
|
|
3188
|
-
*/
|
|
3189
|
-
get $rootVNode() {
|
|
3190
|
-
return this[PARSER_TEMPLATE_TARGET]?.root;
|
|
3191
|
-
}
|
|
3192
|
-
/**
|
|
3193
|
-
* 添加节点变更监听
|
|
3194
|
-
* @param ref ref标记
|
|
3195
|
-
* @param callBack
|
|
3196
|
-
* @returns 销毁方法
|
|
3197
|
-
*/
|
|
3198
|
-
$watchNode(ref, callBack) {
|
|
3199
|
-
if (this[PARSER_TEMPLATE_TARGET]) {
|
|
3200
|
-
this[PARSER_TEMPLATE_TARGET]?.addNodeWatcher(ref, callBack);
|
|
3201
|
-
return () => {
|
|
3202
|
-
this[PARSER_TEMPLATE_TARGET]?.removeNodeWatcher(ref, callBack);
|
|
3203
|
-
};
|
|
3204
|
-
}
|
|
3205
|
-
else {
|
|
3206
|
-
logger.warn(LOGTAG, `该组件还未挂载,不可以进行节点观察监听`);
|
|
3207
|
-
}
|
|
3208
|
-
}
|
|
3209
|
-
/**
|
|
3210
|
-
* 观察值变更
|
|
3211
|
-
* @param express
|
|
3212
|
-
* @param callBack
|
|
3213
|
-
* @param forceCallBack 即使值相同也要强制触发callback
|
|
3214
|
-
* @returns 销毁watcher
|
|
3215
|
-
*/
|
|
3216
|
-
$watch(express, callBack, forceCallBack) {
|
|
3217
|
-
let watcher = new Watcher(express, (newVal, oldVal) => {
|
|
3218
|
-
callBack(newVal, oldVal);
|
|
3219
|
-
}, undefined, forceCallBack);
|
|
3220
|
-
this[PRIVATE_WATCHERS].push(watcher);
|
|
3221
|
-
return () => {
|
|
3222
|
-
watcher.destroy();
|
|
3223
|
-
remove(this[PRIVATE_WATCHERS], watcher);
|
|
3224
|
-
};
|
|
3225
|
-
}
|
|
3226
|
-
/**
|
|
3227
|
-
* 事件注册
|
|
3228
|
-
* @param eventName
|
|
3229
|
-
* @param callBack
|
|
3230
|
-
*/
|
|
3231
|
-
$on(eventName, callBack) {
|
|
3232
|
-
let callBacks = this[EVENT_DATA_KEY].get(eventName);
|
|
3233
|
-
if (callBacks === undefined) {
|
|
3234
|
-
callBacks = [];
|
|
3235
|
-
this[EVENT_DATA_KEY].set(eventName, callBacks);
|
|
3236
|
-
}
|
|
3237
|
-
if (callBacks?.includes(callBack) === false) {
|
|
3238
|
-
callBacks.push(callBack);
|
|
3239
|
-
}
|
|
3240
|
-
}
|
|
3241
|
-
/**
|
|
3242
|
-
* 事件卸载
|
|
3243
|
-
* @param eventName
|
|
3244
|
-
* @param callBack
|
|
3245
|
-
*/
|
|
3246
|
-
$off(eventName, callBack) {
|
|
3247
|
-
let callBacks = this[EVENT_DATA_KEY].get(eventName);
|
|
3248
|
-
if (callBacks) {
|
|
3249
|
-
if (callBack) {
|
|
3250
|
-
remove(callBacks, callBack);
|
|
3251
|
-
}
|
|
3252
|
-
else {
|
|
3253
|
-
callBacks.length = 0;
|
|
3254
|
-
}
|
|
3255
|
-
}
|
|
3256
|
-
}
|
|
3257
|
-
/**
|
|
3258
|
-
* 触发事件
|
|
3259
|
-
* @param eventName 事件名称
|
|
3260
|
-
* @param param 参数
|
|
3261
|
-
* @param targetEvent event
|
|
3262
|
-
*/
|
|
3263
|
-
$trigger(eventName, param, targetEvent) {
|
|
3264
|
-
//销毁节点不做任何事件响应
|
|
3265
|
-
if (this.$root === undefined) {
|
|
3266
|
-
return;
|
|
3267
|
-
}
|
|
3268
|
-
let e = {
|
|
3269
|
-
eventName,
|
|
3270
|
-
stopPropagation: targetEvent?.stopPropagation ?? (() => { }),
|
|
3271
|
-
preventDefault: targetEvent?.preventDefault ?? (() => { }),
|
|
3272
|
-
data: param,
|
|
3273
|
-
target: targetEvent?.target ?? this.$rootVNode,
|
|
3274
|
-
event: targetEvent?.event
|
|
3275
|
-
};
|
|
3276
|
-
//虚拟节点的事件传播,不是通过on进行传递,需要容器介质,保证不随着组件销毁
|
|
3277
|
-
if (this.$rootVNode && this.$rootVNode.parent && this.$rootVNode.parent instanceof VNode.Component) {
|
|
3278
|
-
if (this[PARSER_TEMPLATE_TARGET]?.render.triggerEvent(this.$rootVNode.parent, eventName, e) === false)
|
|
3279
|
-
return;
|
|
3280
|
-
}
|
|
3281
|
-
//实例事件响应
|
|
3282
|
-
let callBacks = this[EVENT_DATA_KEY].get(eventName);
|
|
3283
|
-
if (callBacks?.length) {
|
|
3284
|
-
[...callBacks].forEach((m) => {
|
|
3285
|
-
m(e);
|
|
3286
|
-
});
|
|
3287
|
-
}
|
|
3288
|
-
//全局补充
|
|
3289
|
-
let globalCallBacks = this[EVENT_DATA_KEY].get("*");
|
|
3290
|
-
if (globalCallBacks?.length) {
|
|
3291
|
-
[...globalCallBacks].forEach((m) => {
|
|
3292
|
-
m(e);
|
|
3293
|
-
});
|
|
3294
|
-
}
|
|
3295
|
-
}
|
|
3296
|
-
/**
|
|
3297
|
-
* 主动渲染(仅渲染,一般适用于模板区域的热更新使用/或动态装载等复杂场景)
|
|
3298
|
-
* @param newTemplate 可指定新的模板,否则按照原模板
|
|
3299
|
-
* @param keepalive 渲染新模板时,是否要保留之前的存活组件(高级用法)
|
|
3300
|
-
* @returns
|
|
3301
|
-
*/
|
|
3302
|
-
$render(newTemplate, keepalive) {
|
|
3303
|
-
//之所以 将template放在前置,而不是判断root之后,是为了keepalive组件的热更新
|
|
3304
|
-
newTemplate ??= this.template;
|
|
3305
|
-
if (typeof newTemplate === "function") {
|
|
3306
|
-
this.template = newTemplate(RENDER_HANDLER);
|
|
3307
|
-
}
|
|
3308
|
-
else {
|
|
3309
|
-
this.template = newTemplate;
|
|
3310
|
-
}
|
|
3311
|
-
if (this.$root === undefined) {
|
|
3312
|
-
//未挂在/已销毁/已压栈,不做rerender
|
|
3313
|
-
return;
|
|
3314
|
-
}
|
|
3315
|
-
//执行一次render,则初始化一次template
|
|
3316
|
-
this.template ??= [];
|
|
3317
|
-
this[PARSER_TEMPLATE_TARGET]?.reSetAsts(this.template, keepalive);
|
|
3318
|
-
this[PARSER_TEMPLATE_TARGET] ??= new ParserTemplate(this.template, this, this.$root);
|
|
3319
|
-
this[PARSER_TEMPLATE_TARGET].parser();
|
|
3320
|
-
this[PARSER_TEMPLATE_TARGET].mount(this.$root);
|
|
3321
|
-
}
|
|
3322
|
-
/**
|
|
3323
|
-
* 生命周期函数(完成初始化)
|
|
3324
|
-
*/
|
|
3325
|
-
created() { }
|
|
3326
|
-
/**
|
|
3327
|
-
* 生命周期函数(完成挂载)
|
|
3328
|
-
*/
|
|
3329
|
-
mounted() { }
|
|
3330
|
-
/**
|
|
3331
|
-
* 生命周期函数(销毁前)
|
|
3332
|
-
*/
|
|
3333
|
-
beforeDestroy() { }
|
|
3334
|
-
/**
|
|
3335
|
-
* 睡眠时,在启用keepalive属性时才会触发该周期
|
|
3336
|
-
*/
|
|
3337
|
-
sleeped() { }
|
|
3338
|
-
/**
|
|
3339
|
-
* 唤醒时,在启用keepalive属性时才会触发该周期
|
|
3340
|
-
*/
|
|
3341
|
-
wakeup() { }
|
|
3342
|
-
/**
|
|
3343
|
-
* 生命周期函数(销毁后)
|
|
3344
|
-
*/
|
|
3345
|
-
destroyed() { }
|
|
3346
|
-
}
|
|
3347
|
-
//#region 全局组件注册
|
|
3348
|
-
//全局组件注册
|
|
3349
|
-
const globalComponents = {};
|
|
3350
|
-
/**
|
|
3351
|
-
* 注册全局组件
|
|
3352
|
-
* @param componentsOrName 组件名/列表
|
|
3353
|
-
* @param component 组件
|
|
3354
|
-
*/
|
|
3355
|
-
function registerGlobalComponent(componentsOrName, component) {
|
|
3356
|
-
if (typeof componentsOrName === "string") {
|
|
3357
|
-
if (component) {
|
|
3358
|
-
globalComponents[componentsOrName] = component;
|
|
3359
|
-
}
|
|
3360
|
-
}
|
|
3361
|
-
else {
|
|
3362
|
-
for (let name in componentsOrName) {
|
|
3363
|
-
globalComponents[name] = componentsOrName[name];
|
|
3364
|
-
}
|
|
3365
|
-
}
|
|
3366
|
-
}
|
|
3367
|
-
/**
|
|
3368
|
-
* 根据注册key获取组件
|
|
3369
|
-
* @param name 组件名称
|
|
3370
|
-
* @returns 组件
|
|
3371
|
-
*/
|
|
3372
|
-
function getGlobalComponent(key) {
|
|
3373
|
-
return globalComponents[key];
|
|
3374
|
-
}
|
|
3375
|
-
//#endregion
|
|
3376
|
-
//#region 工具方法
|
|
3377
|
-
/**
|
|
3378
|
-
* 睡眠事件穿透广播
|
|
3379
|
-
* @param vnode
|
|
3380
|
-
*/
|
|
3381
|
-
function sleepNotify(vnode) {
|
|
3382
|
-
vnode.childrens?.forEach((m) => {
|
|
3383
|
-
if (m instanceof VNode.Component) {
|
|
3384
|
-
m.component?.sleeped();
|
|
3385
|
-
}
|
|
3386
|
-
sleepNotify(m);
|
|
3387
|
-
});
|
|
3388
|
-
}
|
|
3389
|
-
/**
|
|
3390
|
-
* 唤醒事件穿透广播
|
|
3391
|
-
* @param vnode
|
|
3392
|
-
*/
|
|
3393
|
-
function weakupNotify(vnode) {
|
|
3394
|
-
vnode.childrens?.forEach((m) => {
|
|
3395
|
-
if (m instanceof VNode.Component) {
|
|
3396
|
-
m.component?.wakeup();
|
|
3397
|
-
}
|
|
3398
|
-
weakupNotify(m);
|
|
3399
|
-
});
|
|
3400
|
-
}
|
|
3401
|
-
//#endregion
|
|
3402
|
-
//#region 默认集成组件
|
|
3403
|
-
/**
|
|
3404
|
-
* 动态组件容器
|
|
3405
|
-
*/
|
|
3406
|
-
class ComponentContainer extends Component {
|
|
3407
|
-
template = [];
|
|
3408
|
-
cache = new Map();
|
|
3409
|
-
mounted() {
|
|
3410
|
-
this.$watch(() => this.props.name, (componentName) => {
|
|
3411
|
-
this.loadComponent(componentName);
|
|
3412
|
-
});
|
|
3413
|
-
this.loadComponent(this.props.name);
|
|
3414
|
-
}
|
|
3415
|
-
propsVaule;
|
|
3416
|
-
created() {
|
|
3417
|
-
let propsData = {};
|
|
3418
|
-
if (!this.props.props) {
|
|
3419
|
-
Object.keys(this.props).forEach((p) => {
|
|
3420
|
-
//过滤
|
|
3421
|
-
if (typeof p !== "string")
|
|
3422
|
-
return;
|
|
3423
|
-
let pName = toLowerCase(p);
|
|
3424
|
-
if (pName === "transition-name" || pName === "name" || pName === "keep-alive" || pName === "ref")
|
|
3425
|
-
return;
|
|
3426
|
-
propsData[p] = this.props[p];
|
|
3427
|
-
//单项数据同步
|
|
3428
|
-
this.$watch(() => this.props[p], () => {
|
|
3429
|
-
this.propsVaule[p] = this.props[p];
|
|
3430
|
-
});
|
|
3431
|
-
});
|
|
3432
|
-
this.propsVaule = observer(propsData);
|
|
3433
|
-
}
|
|
3434
|
-
}
|
|
3435
|
-
async loadComponent(componentName) {
|
|
3436
|
-
if (!componentName) {
|
|
3437
|
-
this.$render([], this.isKeepAlive);
|
|
3438
|
-
return;
|
|
3439
|
-
}
|
|
3440
|
-
let cacheComponent;
|
|
3441
|
-
if (this.isKeepAlive) {
|
|
3442
|
-
let cacheComponent = this.cache.get(componentName);
|
|
3443
|
-
if (cacheComponent) {
|
|
3444
|
-
this.$render([createComponent(cacheComponent, { "transition-name": this.props["transition-name"] })], true);
|
|
3445
|
-
return;
|
|
3446
|
-
}
|
|
3447
|
-
}
|
|
3448
|
-
let hostComponents = this.$rootVNode?.parent?.[VNode.PARSERKEY]?.ob.components;
|
|
3449
|
-
let component = hostComponents?.[componentName];
|
|
3450
|
-
if (component === undefined) {
|
|
3451
|
-
component = getGlobalComponent(componentName);
|
|
3452
|
-
}
|
|
3453
|
-
if (component) {
|
|
3454
|
-
if (!(JOKER_COMPONENT_TAG in component)) {
|
|
3455
|
-
component = (await component()).default;
|
|
3456
|
-
}
|
|
3457
|
-
cacheComponent = new component(this.props.props || this.propsVaule, this.$sections, this.isKeepAlive);
|
|
3458
|
-
//事件向上穿透广播
|
|
3459
|
-
cacheComponent.$on("*", (e) => {
|
|
3460
|
-
this.$trigger(e.eventName, e.data, e);
|
|
3461
|
-
});
|
|
3462
|
-
this.isKeepAlive && this.cache.set(componentName, cacheComponent);
|
|
3463
|
-
this.$render([createComponent(cacheComponent, { "transition-name": this.props["transition-name"] })], this.isKeepAlive);
|
|
3464
|
-
}
|
|
3465
|
-
else {
|
|
3466
|
-
logger.warn("component", `未找到${componentName}的组件`);
|
|
3467
|
-
}
|
|
3468
|
-
}
|
|
3469
|
-
beforeDestroy() {
|
|
3470
|
-
this.removeCache();
|
|
3471
|
-
}
|
|
3472
|
-
removeCache(componentName) {
|
|
3473
|
-
if (componentName) {
|
|
3474
|
-
let cacheComponent = this.cache.get(componentName);
|
|
3475
|
-
this.cache.delete(componentName);
|
|
3476
|
-
if (cacheComponent) {
|
|
3477
|
-
cacheComponent.$destroy(true);
|
|
3478
|
-
}
|
|
3479
|
-
}
|
|
3480
|
-
else {
|
|
3481
|
-
this.cache.forEach((value) => {
|
|
3482
|
-
value.$destroy(true);
|
|
3483
|
-
});
|
|
3484
|
-
this.cache.clear();
|
|
3485
|
-
}
|
|
3486
|
-
}
|
|
3487
|
-
}
|
|
3488
|
-
/**
|
|
3489
|
-
* 虚拟模板容器,用于进行归组,作为组件配置属性
|
|
3490
|
-
*/
|
|
3491
|
-
class Template extends Component {
|
|
3492
|
-
template = function () {
|
|
3493
|
-
return [createCommand("RenderSection")];
|
|
3494
|
-
};
|
|
3495
|
-
}
|
|
3496
|
-
registerGlobalComponent({
|
|
3497
|
-
template: Template,
|
|
3498
|
-
component: ComponentContainer
|
|
3499
|
-
});
|
|
3500
|
-
//#endregion
|
|
3501
|
-
|
|
3502
|
-
const HMR_MAP = new Map();
|
|
3503
|
-
const HMR_RENDER_MAP = new Map();
|
|
3504
|
-
const HMR_COMPONENT_MAP = new Map();
|
|
3505
|
-
/**
|
|
3506
|
-
* 热更新助手(热更新使用)(构建时会按需剔除)
|
|
3507
|
-
*/
|
|
3508
|
-
let __JOKER_HMR_RUNTIME = {
|
|
3509
|
-
recordRender: (id, template) => {
|
|
3510
|
-
HMR_RENDER_MAP.set(id, template);
|
|
3511
|
-
},
|
|
3512
|
-
recordComponent: (id, component) => {
|
|
3513
|
-
HMR_COMPONENT_MAP.set(id, component);
|
|
3514
|
-
},
|
|
3515
|
-
record: (id, component) => {
|
|
3516
|
-
if (HMR_MAP.get(id) === undefined) {
|
|
3517
|
-
HMR_MAP.set(id, new Set());
|
|
3518
|
-
}
|
|
3519
|
-
HMR_MAP.get(id).add(component);
|
|
3520
|
-
component.$on("destroy", () => {
|
|
3521
|
-
HMR_MAP.get(id)?.delete(component);
|
|
3522
|
-
});
|
|
3523
|
-
},
|
|
3524
|
-
reload: (id, component) => {
|
|
3525
|
-
let recode = HMR_COMPONENT_MAP.get(id);
|
|
3526
|
-
if (!recode)
|
|
3527
|
-
return;
|
|
3528
|
-
//1. 更新值
|
|
3529
|
-
recode.component = component;
|
|
3530
|
-
//2. 更新已渲染的
|
|
3531
|
-
let rendered = HMR_MAP.get(id);
|
|
3532
|
-
if (!rendered)
|
|
3533
|
-
return;
|
|
3534
|
-
let reloadRecodes = Array.from(rendered);
|
|
3535
|
-
//刷新/重载组件时会重新完成map绘制
|
|
3536
|
-
rendered.clear();
|
|
3537
|
-
//引用类型存在循环
|
|
3538
|
-
reloadRecodes.forEach((c) => {
|
|
3539
|
-
//未被销毁
|
|
3540
|
-
if (c.$root) {
|
|
3541
|
-
if (c.$rootVNode?.parent) {
|
|
3542
|
-
let parent = c.$rootVNode.parent;
|
|
3543
|
-
if (parent instanceof VNode.Component &&
|
|
3544
|
-
parent[VNode.PARSERKEY] &&
|
|
3545
|
-
//直接指向内存的组件,无法重新实例化
|
|
3546
|
-
parent[VNode.PARSERKEY].canReload) {
|
|
3547
|
-
parent[VNode.PARSERKEY].reload();
|
|
3548
|
-
}
|
|
3549
|
-
else {
|
|
3550
|
-
//无法更新
|
|
3551
|
-
location.reload();
|
|
3552
|
-
return;
|
|
3553
|
-
}
|
|
3554
|
-
}
|
|
3555
|
-
else {
|
|
3556
|
-
//无根的话只能重载
|
|
3557
|
-
location.reload();
|
|
3558
|
-
return;
|
|
3559
|
-
}
|
|
3560
|
-
}
|
|
3561
|
-
});
|
|
3562
|
-
},
|
|
3563
|
-
rerender: (id, template) => {
|
|
3564
|
-
let prevRender = HMR_RENDER_MAP.get(id);
|
|
3565
|
-
//更新render根方法,以实现未实例化的组件更新
|
|
3566
|
-
if (prevRender) {
|
|
3567
|
-
prevRender.render = template;
|
|
3568
|
-
}
|
|
3569
|
-
//完成已实例化的组件的更新
|
|
3570
|
-
HMR_MAP.get(id)?.forEach((c) => {
|
|
3571
|
-
c.$render(template);
|
|
3572
|
-
});
|
|
3573
|
-
}
|
|
3574
|
-
};
|
|
3575
|
-
|
|
3576
|
-
class EventBus {
|
|
3577
|
-
eventDatas = new Map();
|
|
3578
|
-
on(eventName, callBack) {
|
|
3579
|
-
let callbacks = this.eventDatas.get(eventName);
|
|
3580
|
-
if (callbacks === undefined) {
|
|
3581
|
-
callbacks = [];
|
|
3582
|
-
this.eventDatas.set(eventName, callbacks);
|
|
3583
|
-
}
|
|
3584
|
-
callbacks.push({ callBack });
|
|
3585
|
-
}
|
|
3586
|
-
once(eventName, callBack) {
|
|
3587
|
-
let callbacks = this.eventDatas.get(eventName);
|
|
3588
|
-
if (callbacks === undefined) {
|
|
3589
|
-
callbacks = [];
|
|
3590
|
-
this.eventDatas.set(eventName, callbacks);
|
|
3591
|
-
}
|
|
3592
|
-
callbacks.push({ callBack, once: true });
|
|
3593
|
-
}
|
|
3594
|
-
off(eventName, callBack) {
|
|
3595
|
-
if (eventName === undefined) {
|
|
3596
|
-
this.eventDatas.clear();
|
|
3597
|
-
return;
|
|
3598
|
-
}
|
|
3599
|
-
if (callBack) {
|
|
3600
|
-
let callBacks = this.eventDatas.get(eventName);
|
|
3601
|
-
let removeItem = callBacks?.find((m) => m.callBack === callBack);
|
|
3602
|
-
removeItem && remove(callBacks, removeItem);
|
|
3603
|
-
}
|
|
3604
|
-
else {
|
|
3605
|
-
// off all
|
|
3606
|
-
this.eventDatas.delete(eventName);
|
|
3607
|
-
}
|
|
3608
|
-
}
|
|
3609
|
-
trigger(eventName, param) {
|
|
3610
|
-
let callBacks = this.eventDatas.get(eventName);
|
|
3611
|
-
if (callBacks && callBacks.length) {
|
|
3612
|
-
let i = 0, callTimes = 0, isBreak = false;
|
|
3613
|
-
while (callBacks[i]) {
|
|
3614
|
-
let item = callBacks[i];
|
|
3615
|
-
item.callBack({
|
|
3616
|
-
stopPropagation: () => (isBreak = true),
|
|
3617
|
-
callTimes
|
|
3618
|
-
}, param);
|
|
3619
|
-
if (item.once) {
|
|
3620
|
-
remove(callBacks, item);
|
|
3621
|
-
}
|
|
3622
|
-
else {
|
|
3623
|
-
i++;
|
|
3624
|
-
}
|
|
3625
|
-
if ((isBreak)) {
|
|
3626
|
-
return false;
|
|
3627
|
-
}
|
|
3628
|
-
}
|
|
3629
|
-
}
|
|
3630
|
-
}
|
|
3631
|
-
}
|
|
3632
|
-
|
|
3633
|
-
export { Component, ComponentContainer, Dep, EventBus, IContainer, JOKER_COMPONENT_TAG, JOKER_VNODE_TAG, OBJECTPROXY_DEPID, ParserTemplate, SCOPE_ID, ShallowObserver, Template, VNode, Watcher, __JOKER_HMR_RUNTIME, combinedReply, defineObserverProperty, getGlobalComponent, isObserverData, observer, registerGlobalComponent, registerGlobalFunction, registerOtherWindowDep, removeOtherWindowDep };
|
|
1
|
+
import{EXPRESSHANDLERTAG as e,createFuntionBody as t,AST as s,RENDER_HANDLER as n,createComponent as i,createCommand as r}from"@joker.front/ast";export{AST,EXPRESSHANDLERTAG,RENDER_HANDLER,createCodeFunction,createCommand,createComment,createComponent,createElement,createFuntionBody,createText}from"@joker.front/ast";const o=new Map,a=new Map,h=new Map;let d={recordRender:(e,t)=>{a.set(e,t)},recordComponent:(e,t)=>{h.set(e,t)},record:(e,t)=>{void 0===o.get(e)&&o.set(e,new Set),o.get(e).add(t),t.$on("destroy",(()=>{o.get(e)?.delete(t)}))},reload:(e,t)=>{let s=h.get(e);if(!s)return;s.component=t;let n=o.get(e);if(!n)return;let i=Array.from(n);n.clear(),i.forEach((e=>{if(e.$root){if(!e.$rootVNode?.parent)return window.onbeforeunload=null,void location.reload();{let t=e.$rootVNode.parent;if(!(t instanceof X.Component&&t[X.PARSERKEY]&&t[X.PARSERKEY].canReload))return window.onbeforeunload=null,void location.reload();t[X.PARSERKEY].reload()}}}))},rerender:(e,t)=>{let s=a.get(e);s&&(s.render=t),o.get(e)?.forEach((e=>{e.$render(t)}))}};function l(e){return null!==e&&"object"==typeof e}function c(e,t){Object.getOwnPropertyNames(e).forEach((s=>{t(s,e[s])}))}function u(e){return"[object Object]"===Object.prototype.toString.call(e)}function f(e){if(null===e)return e;if("object"!=typeof e)return e;let t;t=Array.isArray(e)?[]:{};let s=Object.keys(e);for(let n of s){let s=e[n];t[n]="object"==typeof s?f(s):s}return t}function p(e,t,s){return Array.isArray(e)&&Array.isArray(t)?function(e,t,s){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n++)if(!1===m(e[n],t[n],s))return!1;return!0}(e,t,s):m(e,t,s)}function m(e,t,s){let n=l(e),i=l(t);if(n&&i){if(u(e)&&u(t)){let n=Object.keys(e);if(n.length!==Object.keys(t).length)return!1;if(s){for(let s of n)if(e[s]!==t[s])return!1;return!0}return JSON.stringify(e)===JSON.stringify(t)}return e===t}return!n&&!i&&String(e)===String(t)}function y(e,t){let s=e.indexOf(t);return s>-1&&e.splice(s,1),e}function E(e,t){let s=e.findIndex((e=>t(e)));return s>-1&&e.splice(s,1),e}function v(e=32){let t=[],s=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"];for(let n=0;n<e;n++){let e=Math.round(Math.random()*(s.length-1));t.push(s[e])}return t.join("")}function g(e){return!e||""===e.trim()}function b(e,t="-"){return(e=e||"").split(/(?=[A-Z])/).map((e=>e.toLowerCase())).join(t)}let N=(...e)=>{},w="warn";const R=["silent","error","warn","info"];function $(){let e=new Date;function t(e,t=2){return e.toString().padStart(t,"0")}return t(e.getHours())+":"+t(e.getMinutes())+":"+t(e.getSeconds())+":"+t(e.getMilliseconds(),3)}function A(e,t,s,n){R.indexOf(e)<=R.indexOf(w)&&(void 0===n?console[e](`${$()} [${t}]:`,s):console[e](`${$()} [${t}]:`,s,n))}let C={info:function(e,t,s){A("info",e,t,s)},warn:function(e,t,s){A("warn",e,t,s)},error:function(e,t,s){A("error",e,t,s)},setLoggerLeve:function(e){w=e}};const O={lt:"<",gt:">",nbsp:" ",amp:"&",quot:'"',"#39":"'"};function x(e){return e.replace(/&(lt|gt|nbsp|amp|quot|#39);/gi,((e,t)=>O[t]||""))}class S{id="production"===process.env.NODE_ENV?"":v();static target;watchers=new Map;depend(e){S.target?.addDep(this,e)}addWatcher(e,t){let s=this.watchers.get(e)||[];s.push(t),this.watchers.set(e,s)}removeWatcher(e,t){let s=this.watchers.get(e);s&&y(s,t)}notify(e){let t=this.watchers.get(e);if(t){E(t,(e=>e.isDestroy)),[...t].forEach((e=>{!1===e.isDestroy&&e.update()}))}}}const P=Symbol.for("__JOKER_OBJECT_PROXY_DEP_ID__"),T=Symbol.for("__JOKER_OBJECT_PROXY_DATA_KEY__"),D=Symbol.for("__JOKER_OBJECTPROXY_DEPLEVE_ID__");function _(e){return l(e)&&(Array.isArray(e)||u(e))&&Object.isExtensible(e)&&!Object.isFrozen(e)&&!(e instanceof Element)&&!(q in e)&&!(M in e)&&!(Je in e)}function k(e){if(K(e))return e;let t=Reflect.get(e,T);if(t)return t;let s=new S,n=!0,i=new Proxy(e,{get(e,t,n){if(t===T)return;if(t===P)return s;if(t===D)return;let i=Reflect.get(e,t);return!1===function(e,t){return t in e}(e,t)&&"length"!==t||(s.depend(t),_(i)&&K(i)?.depend(D)),i},set(e,t,i){if(n)return Reflect.set(e,t,i),!0;_(i)&&(i=W(i));let r=!1===function(e,t){return Object.prototype.hasOwnProperty.call(e,t)}(e,t),o=Reflect.get(e,t)!==i;return Reflect.set(e,t,i),(o||"length"===t&&Array.isArray(e))&&Y(s,t),Array.isArray(e)?"length"===t&&Y(s,D):r&&Y(s,D),!0},deleteProperty:(e,t)=>(Reflect.deleteProperty(e,t),!1===Array.isArray(e)&&Y(s,D),!0)});var r,o,a,h;r=e,o=T,a=i,h=!1,Object.defineProperty(r,o,{value:a,enumerable:h,writable:!0,configurable:!0});for(let t in e){let s=e[t];_(s)&&!K(s)&&(i[t]=k(e[t]))}return n=!1,i}function K(e){if(l(e)){let t=Reflect.get(e,P);if(t)return t}}function W(e,t=!1){if(!1===_(e))throw new Error("当前传入的数据不是正确的数据类型,必须是数组或者对象");return k(t?f(e):e)}function V(e,t,s){let n=s;_(s)&&(n=W(s));let i=new S;Object.defineProperty(e,t,{enumerable:!0,configurable:!0,get:()=>(i.depend(t),_(n)&&K(n)?.depend(D),n),set:e=>{e!==n&&(_(e)&&(e=W(e)),n=e,Y(i,t))}})}const M=Symbol.for("JOKER_SHALLOW_OBSERVER");class L{data;[M]=!0;dep=new S;constructor(e){this.data=e}isChanged=!1;get value(){return this.dep.depend(D),this.data}set value(e){!1===Object.is(e,this.data)&&(this.isChanged=!0,this.data=e,Y(this.dep,D))}}let I=!1,j=new Map;function Y(e,t){if(!1===I)e.notify(t);else{let s=j.get(e);void 0===s&&(s=[],j.set(e,s)),!1===s.includes(t)&&s.push(t)}}function H(e){I=!0;try{e()}catch(e){return I=!1,j.clear(),void C.error("数据劫持","数据劫持组合回复在做变更采集时,遇到了阻塞错误,不做响应,请检查",e)}I=!1,function(e){let t=[],s=[];e.forEach(((e,s)=>{e.forEach((e=>{t.push(...s.watchers.get(e)||[])}))})),t.forEach((e=>{s.includes(e)||(!1===e.isDestroy&&e.update(),s.push(e))}))}(j),j.clear()}function B(e){return void 0!==K(e)}const J="数据观察";class F{ob;updateCallBack;forceCallBack;id=v();getter;value;isDestroy=!1;updating=!1;runRelations=new Map;relations=new Map;constructor(e,t,s,n){if(this.ob=e,this.updateCallBack=t,this.forceCallBack=n,void 0===e)throw new Error("无法对underfind进行变更观察");if(void 0===s)this.getter=e=>e;else if("function"==typeof s)this.getter=s;else{let e=function(e){if(/[^\w.$]/.test(e))return;let t=e.split(".");return function(e){let s=e;return t.forEach((e=>{s&&(s=s[e])})),s}}(s);if(void 0===e)throw new Error(s+"解析失败,无法明确读取表达式,请检查expOrFn参数,或采用function模式");this.getter=e}void 0===this.getter&&C.error(J,"getter创建失败",arguments),this.value=this.getValue()}getValue(){if(void 0===this.getter)return;S.target=this;let e,t="function"==typeof this.ob?this.ob():this.ob;try{e=this.getter.call(t,t)}catch(e){throw C.error(J,`获取值失败,执行方法:${this.getter.toString()}`),e}return S.target=void 0,this.clearnDeps(),e}addDep(e,t){let s=this.runRelations.get(e);if(void 0===s||!1===s.includes(t)){s=s||[],s.push(t),this.runRelations.set(e,s);let n=this.relations.get(e);void 0!==n&&!1!==n.includes(t)||e.addWatcher(t,this)}}update(){if(this.updating)return;let e=this.getValue(),t=this.value;if(this.forceCallBack||e!==t||l(e)){if(this.value=e,e!==t&&!this.forceCallBack&&p(e,t,!0))return;this.updating=!0;try{this.updateCallBack(e,t)}catch(e){throw e}finally{this.updating=!1}}}destroy(){this.relations.forEach(((e,t)=>{for(let s of e)t.removeWatcher(s,this)})),this.isDestroy=!0,this.relations.clear(),this.runRelations.clear(),this.ob=void 0,this.value=void 0,this.getter=void 0}clearnDeps(){this.relations.forEach(((e,t)=>{let s=this.runRelations.get(t);for(let n of e)s?!1===s.includes(n)&&t.removeWatcher(n,this):t.removeWatcher(n,this)})),this.relations.clear(),this.relations=this.runRelations,this.runRelations=new Map}}var G;!function(e){let t=new Map;e.bind=function(e){return{to:s=>{if(t.has(e))throw new Error(`TagId:${e.toString()}已注入实现类,请勿重复注入。`);t.set(e,s)}}},e.get=function(e,...s){let n=t.get(e);if(n)return new n(...s)}}(G||(G={}));const q=Symbol.for("JOKER_VNODE_TAG");var X;!function(e){e.PARSERKEY=Symbol.for("JOKER_PARSER_KEY");class t{parent;[q]=!0;static;output;[e.PARSERKEY];childrens;sleep=!1;constructor(e){this.parent=e}get prev(){if(this.parent)return this.parent.childrens?.[this.parent.childrens?.indexOf(this)-1]}get next(){if(this.parent)return this.parent.childrens?.[this.parent.childrens?.indexOf(this)+1]}closest(t,s){if(!0===t(this))return this;let n=this.parent;for(;n;){if(s&&n instanceof e.Root)return;if(!0===t(n))return n;n=n.parent}}find(e,t,s){let n=s??[];if(t??=this.childrens,t)for(let s of t){!0===e(s)&&n.push(s),s.childrens&&this.find(e,s.childrens,n)}return n}contains(e,t){if(t??=this.childrens,t)for(let s of t){if(!0===e(s))return!0;if(s.childrens&&s.childrens.length&&this.contains(e,s.childrens))return!0}return!1}first(e,t){if(t??=this.childrens,t)for(let s of t){if(!0===e(s))return s;if(s.childrens&&s.childrens.length){let t=this.first(e,s.childrens);if(t)return t}}}}e.Node=t;e.Root=class extends t{childrens=[];component;constructor(){super()}};e.Text=class extends t{text;static=!0;constructor(e,t){super(t),this.text=e}};e.Html=class extends t{html;notShadow;static=!0;constructor(e,t,s){super(t),this.html=e,this.notShadow=s}};e.Comment=class extends t{text;static=!0;constructor(e,t){super(t),this.text=e}};e.Element=class extends t{tagName;static=!0;attributes={};childrens=[];events=[];_assistEventCache;constructor(e,t){super(t),this.tagName=e}};e.Component=class extends t{name;component;events=[];propValues={};keepalive;get firstElement(){if(this.childrens){let t=s=>{for(let n of s){if(n instanceof e.Element)return n;if(n.childrens){let e=t(n.childrens);if(e)return e}}};return t(this.childrens)}}get rootElements(){if(this.childrens){let t=[],s=n=>{for(let i of n)i instanceof e.Element?t.push(i):i.childrens&&s(i.childrens)};return s(this.childrens),t}return[]}};e.Condition=class extends t{cmdName;result=!1;childrens=[];isShow=!1;constructor(e,t){super(t),this.cmdName=e}};e.List=class extends t{childrens=[]};e.ListItem=class extends t{ob;childrens=[];constructor(e,t){super(t),this.ob=e}};e.RenderSection=class extends t{id="unknown";params=[];section;childrens=[];ob;constructor(e,t){super(t),"string"==typeof e?this.id=e:this.section=e}}}(X||(X={}));const z="DOM渲染",Z=["script","style","textarea","pre"];let Q=0;var U;function ee(e,t,s){return`${e}-${t}-${s}`}function te(e,t,s,n){e._assistEventCache??=[],e._assistEventCache.push([t,s]),document.body.addEventListener(t,s,n)}function se(e,t,s){e._assistEventCache&&t&&s?(E(e._assistEventCache,(e=>e[0]===t&&e[1]===s)),document.body.removeEventListener(t,s)):(e._assistEventCache?.forEach((e=>{document.body.removeEventListener(e[0],e[1])})),e._assistEventCache&&(e._assistEventCache.length=0),e._assistEventCache=void 0)}!function(e){e.IRENDERIOCTAGID=Symbol.for("JOKER_IRENDERIOC_TAGID"),e.ROOT_CONTAINER="";e.DomRender=class{elements;constructor(){this.elements=document.createDocumentFragment()}mount(e){if(e instanceof Element)e.appendChild(this.elements);else if(e instanceof X.Component)if(e.parent)if(e.output){let t=e.output,s=ae(e)||t.parentNode;s&&s.insertBefore(this.elements,t)}else C.error(z,"组件挂载渲染时发现该节点未定义DOM定位节点",e);else C.error(z,"mount子组件时,发现该组件无父级",e);else C.error(z,"mount只支持挂载到Element或VNode.Node类型数据中",e)}appendNode(e){if(this.renderNode(e),e.output){let t=e.output instanceof HTMLCollection||e.output instanceof NodeList||Array.isArray(e.output)?Array.from(e.output):[e.output];for(let s of t)this.appendNodeChildren(e,s,e.parent)}else C.error(z,"未找自身节点的el属性,无法进行dom挂载",e)}updateNode(e,t){if(e instanceof X.Element)for(let t in e.attributes){let s=e.attributes[t];this.setAttribute(e.output,t,s)}else e instanceof X.Text?e.parent&&e.parent instanceof X.Element&&Z.includes(e.parent.tagName)?(this.removeNode(e),this.appendNode(e)):e.output.textContent=x(e.text||""):e instanceof X.Html?e.notShadow?e.output.innerHTML=e.html:e.output.root.innerHTML=e.html:C.error(z,`该节点不支持${t}的更新`,e)}removeNode(e,t){let s=e.output instanceof HTMLCollection||e.output instanceof NodeList||Array.isArray(e.output)?Array.from(e.output):[e.output];s?.forEach((e=>{e?.remove()})),t||(e instanceof X.Element&&se(e),e.output=void 0)}destroy(){this.elements=void 0}elementToEnter(e,t,s,n){e.output&&this.transitionFrame(e,t,"enter",s,n)}elementToLeave(e,t,s,n){e.output&&this.transitionFrame(e,t,"leave",s,n)}triggerEvent(e,t,s){let n=[];for(let i of e.events){let[r,o]=i;if(r===t){let t=o.modifiers?.includes("self"),a=o.modifiers?.includes("outside");if(t||a){C.warn(z,"事件修饰符:self、outside在组件事件中无法使用,组件无法确认元素",e);continue}let h=s.event;if((h instanceof KeyboardEvent&&["keydown","keypress","keyup"].includes(r)||h instanceof MouseEvent&&["click","dbclick","mouseup","mousedown"].includes(r))&&!1===ie(h,o.modifiers))continue;if(o.callBack(s),o.modifiers?.includes("prevent")&&s.preventDefault(),o.modifiers?.includes("once")&&n.push(i),o.modifiers?.includes("stop"))return s.stopPropagation(),!1}}n.length&&n.forEach((t=>{y(e.events,t)}))}transitionFrame(e,t,s,n,i){re(e,ee(t,s,"from")),n||="transition";let r=e.output.__TRANSITION_EVNETID__=Q++;requestAnimationFrame((()=>{requestAnimationFrame((()=>{if(!e.output)return;re(e,ee(t,s,"active")),oe(e,ee(t,s,"from")),re(e,ee(t,s,"to"));let o=function(e,t){let s=window.getComputedStyle(e),n=e=>(s[e]||"").split(", ");if("transition"===t){let e=n("transitionDelay"),t=n("transitionDuration"),s=he(e,t);if(s>0)return{timeout:s,count:t.length}}else if("animation"===t){let e=n("animationDelay"),t=n("animationDuration"),s=he(e,t);if(s>0)return{timeout:s,count:t.length}}}(e.output,n);if(!o)return void i?.();let a=0,h=()=>{oe(e,ee(t,s,"to")),oe(e,ee(t,s,"active")),e.output&&(e.output.removeEventListener(`${n}end`,d),r===e.output.__TRANSITION_EVNETID__&&i?.())},d=t=>{t.target===e.output&&++a>=o.count&&h()};setTimeout((()=>{a<o.count&&h()}),o.timeout+1),e.output?.addEventListener(`${n}end`,d)}))}))}renderNode(e){if(!e.output)if(e instanceof X.Text)e.parent&&e.parent instanceof X.Element&&Z.includes(e.parent.tagName)?e.output=this.parserHtml(e.text):e.output=document.createTextNode(x(e.text||""));else if(e instanceof X.Html)if(e.notShadow){let t=document.createElement("joker-html-container");t.JOKER_NODE=e,t.innerHTML=e.html,e.output=t}else{let t=document.createElement("joker-html-shadow");t.JOKER_NODE=e,t.style.lineHeight="1",t.root.innerHTML=e.html,e.output=t}else if(e instanceof X.Element){let t;"svg"===e.tagName||e.parent.isSvg?(e.isSvg=!0,t=document.createElementNS("http://www.w3.org/2000/svg",e.tagName)):t=document.createElement(e.tagName);for(let s in e.attributes)this.setAttribute(t,s,e.attributes[s]);t.JOKER_NODE=e,e.output=t,e.events.some((e=>"click"===e[0]&&e[1].modifiers?.includes("outside")))?setTimeout((()=>{this.initElementEvents(t,e)})):this.initElementEvents(t,e)}else e instanceof X.Comment?e.output=document.createComment(e.text):e.output=document.createTextNode("")}initElementEvents(e,t){for(let[s,n]of t.events){let i=n.modifiers?.includes("self"),r=n.modifiers?.includes("outside");i&&r&&(C.warn(z,"事件修饰符:self、outside不可以同时存在,将按照self处理",t),r=!1);let o,a=function(o){if(!(t.sleep||i&&o.target!==e)){if(r){if(o.target===e||e.contains(o.target))return;if(!1===document.contains(o.target))return;if(t.contains((e=>(e.output instanceof HTMLCollection||e.output instanceof NodeList||Array.isArray(e.output)?Array.from(e.output):[e.output]).includes(o.target))))return!0}(o instanceof KeyboardEvent&&["keydown","keypress","keyup"].includes(s)||o instanceof MouseEvent&&["click","dbclick","mouseup","mousedown"].includes(s))&&!1===ie(o,n.modifiers)||(n.callBack({eventName:s,event:o,target:t,preventDefault:()=>o.preventDefault(),stopPropagation:()=>o.stopPropagation(),data:void 0}),n.modifiers?.includes("prevent")&&o.preventDefault(),n.modifiers?.includes("stop")&&o.stopPropagation(),n.modifiers?.includes("once")&&(r?se(t,s,a):e.removeEventListener(s,a)))}};n.modifiers?.includes("passive")&&(o={passive:!0}),r?te(t,s,a,o):e.addEventListener(s,a,o)}}parserHtml(e){var t=document.createElement("div");return t.innerHTML=e,t.childNodes}isCommandGroup(e){return e instanceof X.Component||e instanceof X.Condition||e instanceof X.List||e instanceof X.ListItem||e instanceof X.RenderSection}appendNodeChildren(e,t,s){let n=ae(e);if(n)n.appendChild(t);else if(void 0===s)this.elements.appendChild(t);else if(s)if(s instanceof X.Root){let e=s.parent;if(e&&e instanceof X.Component&&e.output){let s=e.output,n=s.parentNode;if(n)return void n.insertBefore(t,s)}this.elements.appendChild(t)}else if(s instanceof X.Element){let n=s.output;void 0===n&&C.error(z,"appendNodeChildren挂载失败,找不到父节点DOM输出",{parent:s,node:e}),n.appendChild(t)}else if(this.isCommandGroup(s)){let e=s.output,n=e.parentNode;n&&n.insertBefore(t,e)}else C.error(z,"该节点不支持嵌套子集,请检查。",{node:e,parent:s})}setAttribute(e,t,s){if(e)if("boolean"!=typeof s){if("class"===t){if(Array.isArray(s)){let e=[];for(let t of s)if(l(t))for(let s in t)t[s]&&e.push(s);else t&&e.push(t);s=e.join(" ")}else if(l(s)){for(let t in s)s[t]?e.classList.add(t):e.classList.remove(t);return}}else if("style"===t&&l(s)){e.removeAttribute("style");for(let t in s){let n=!1;void 0!==s[t]&&!1!==s[t]||(n=!0);let i=String(s[t]);g(i)&&(n=!0),n||(e.style[t]=i)}return}s=(s??"").toString().trim(),"class"===t&&(s=s.split(/\s/).filter((e=>e.trim())).join(" ")),"value"===t&&"value"in e?e.value=s:e.setAttribute(t,s)}else s?e.setAttribute(t,""):e.removeAttribute(t)}}}(U||(U={}));const ne={enter:"enter",backspace:"delete",tab:"tab",arrowup:"up",arrowdown:"down",arrowleft:"left",arrowright:"right",escape:"esc"," ":"space"};function ie(e,t){if(e instanceof KeyboardEvent){if(void 0===e.key)return!1;for(let s in ne)if(t?.includes(ne[s])&&e.key.toLowerCase()!==s)return!1}else{if(t?.includes("left")&&0!==e.button)return!1;if(t?.includes("right")&&2!==e.button)return!1;if(t?.includes("middle")&&1!==e.button)return!1}return(!t?.includes("ctrl")||!1!==e.ctrlKey)&&((!t?.includes("alt")||!1!==e.altKey)&&(!t?.includes("shift")||!1!==e.shiftKey))}function re(e,t){e.output&&e.output.classList.add(t)}function oe(e,t){e.output&&e.output.classList.remove(t)}function ae(e){if(e instanceof X.Element||e instanceof X.Component){let t=e instanceof X.Component?e.propValues["append-to"]:e.attributes["append-to"];if(t){if(t instanceof X.Element)return t.output;if("string"==typeof t){U.ROOT_CONTAINER&&(t="body"===t?U.ROOT_CONTAINER:`${U.ROOT_CONTAINER} ${t}`);let e=document.querySelector(t);if(e)return e}C.warn(z,"appendTo类型不支持",{appendTo:t,node:e})}}}function he(e,t){for(;e.length<t.length;)e.concat(e);return Math.max(...t.map(((t,s)=>de(t)+de(e[s]))))}function de(e){return"auto"===e?0:1e3*Number(e.slice(0,-1).replace(",","."))}class le extends HTMLElement{root;constructor(){super(),this.root=this.attachShadow({mode:"open"})}}!customElements.get("joker-html-shadow")&&customElements.define("joker-html-shadow",le);const ce={};function ue(e){for(let t in e)ce[t]=e[t]}const fe="Global",pe="渲染核心";function me(t){try{return new Function(e,fe,`return ${t};`)}catch{throw new Error("创建表达式运行方法时出现未知错误,表达式为"+t)}}class ye{ast;ob;parent;ext;ref="";watchers=[];node;constructor(e,t,s,n){this.ast=e,this.ob=t,this.parent=s,this.ext=n,this.parser(),this.afterParser()}beforeDestroy(e){}destroy(e){if(this.clearWatchers(),this.parent.childrens&&this.node){(this.node instanceof X.Element||this.node instanceof X.Component)&&this.ext.removeRef(this.node);let t=()=>{this.parent&&this.node&&(this.beforeDestroy(e),this.destroyChildrens(e),this.ext.render?.removeNode(this.node),this.parent.childrens&&y(this.parent.childrens,this.node),this.notifyNodeWatcher("remove"),this.destroyOtherData())};if(this.ext.nodeTransition(this.node,"leave",void 0,(()=>{t()})))return y(this.parent.childrens,this.node),void this.destroyChildrensWatcher(this.node);t()}else this.destroyOtherData()}destroyWathcers(){this.clearWatchers(),this.destroyChildrensWatcher(this.node)}destroyOtherData(){this.node&&(this.node[X.PARSERKEY]=void 0),this.node=void 0,this.parent=void 0}destroyChildrens(e){for(;this.node?.childrens?.length;){let t=this.node.childrens[0];t[X.PARSERKEY]?t[X.PARSERKEY].destroy(e):y(this.node.childrens,t)}}destroyChildrensWatcher(e){if(e?.childrens?.length)for(let t of e?.childrens)t[X.PARSERKEY]&&(t[X.PARSERKEY].clearWatchers(),this.destroyChildrensWatcher(t))}appendNode(){this.parent.childrens&&this.node&&(this.node[X.PARSERKEY]=this,this.parent.childrens.push(this.node),this.node instanceof X.Element&&this.ob[Be]&&(this.node.attributes["data-scoped-"+this.ob[Be]]=void 0),this.ext.render?.appendNode(this.node),this.notifyNodeWatcher("append"))}afterParser(){this.ext.nodeTransition(this.node,"enter")}notifyNodeWatcher(e,t){this.ext.notifyNodeWatcher(this.ref,this.node,e,t)}runExpress(e,t){try{return me(e).call(t,t,ce)}catch(s){C.error(pe,"运行表达式出现错误:"+e,{ob:t,e:s})}}runExpressWithWatcher(e,t,s,n){let i="string"==typeof e?me(e):e,r=new F((()=>{try{return i.call(t,t,ce)}catch(s){return void C.error(pe,"运行表达式出现错误",{ob:t,e:s,express:e,node:this.node})}}),s,void 0,n);return this.addWatch(r),r.value}addWatch(e){!1===this.watchers.includes(e)&&this.watchers.push(e)}clearWatchers(){this.watchers.forEach((e=>{e.destroy()})),this.watchers.length=0}}class Ee extends ye{parser(){this.node=new X.Text(this.ast.text,this.parent),this.appendNode()}}class ve extends ye{parser(){this.node=new X.Comment(this.ast.text,this.parent),this.appendNode()}}class ge extends ye{parser(){if(this.node=new X.Condition(this.ast.kind,this.parent),"else"!==this.ast.kind){g(this.ast.condition)&&C.error("条件命令",`当前条件命令${this.ast.kind}没有判断条件,请检查`);let e=this.runExpressWithWatcher(this.ast.condition,this.ob,(e=>{let t=!!e;this.node?.result!==t&&(this.node.result=t,this.reloadAllCondition())}));this.node.result=!!e}this.appendNode(),this.renderConditionChildren()}renderConditionChildren(){let e=!1;return this.getPrevIfResult()?e=!1:"else"===this.ast.kind?e=!0:(this.node.result=!!this.runExpress(this.ast.condition,this.ob),this.node.result&&(e=!0)),e!==this.node.isShow&&(this.node.isShow=e,e?this.ast.childrens&&this.ext.parserNodes(this.ast.childrens,this.node,this.ob):this.destroyChildrens(!0),!0)}getPrevIfResult(){if("if"===this.ast.kind)return!1;let e=this.node?.prev;for(;e&&e instanceof X.Condition;){if(e.result)return!0;if("if"===e.cmdName)break;e=e.prev}return!1}reloadAllCondition(){if(this.renderConditionChildren()){let e=this.node?.next;for(;e&&e instanceof X.Condition&&"if"!==e.cmdName;){let t=e[X.PARSERKEY];t&&t instanceof ge&&t.renderConditionChildren(),e=e.next}}}}class be extends ye{parser(){this.node=new X.List(this.parent),this.appendNode(),this.renderChildrens()}renderChildrens(){switch(this.ast.keyType){case"condition":this.renderConditionChildrens();break;case"in":case"of":this.renderInOrOfChildrens()}}renderConditionChildrens(){let t=this.ast.param,s=Object.create(this.ob),n=!!this.runExpressWithWatcher(function(t,s,n){try{return new Function(e,`${e}.${t}=${s}; return ${n};`)}catch{throw new Error(`For循环命令,表达式运行依赖采集出现未知错误,其中letKey:${t},keyVal:${s},condition:${n}`)}}(t.letKey,t.defaultKeyVal,t.condition),s,(()=>{this.clearWatchers(),this.renderChildrens()}),!0),i=0;for(;n;){let e=Object.create(this.ob);V(e,t.letKey,s[t.letKey]);let r=i++;this.renderItem(e,r),this.runExpress(t.step,s),n=!!this.runExpress(t.condition,s),this.runExpressWithWatcher((()=>s[t.letKey]),s,(s=>{e[t.letKey]=s,this.renderItem(e,r)}))}this.destroyOldChildrens(i)}renderInOrOfChildrens(){let e=this.ast.param,t=this.runExpressWithWatcher(e.dataKey,this.ob,(()=>{this.clearWatchers(),this.renderChildrens()})),s=0;if(t&&(Array.isArray(t)||u(t)))for(let n in t){let i=Object.create(this.ob),r=Array.isArray(t)?Number(n):n;e.indexKey&&V(i,e.indexKey,r),e.itemKey&&V(i,e.itemKey,t[n]);let o=s++;this.renderItem(i,o),e.itemKey&&this.runExpressWithWatcher((()=>t[r]),t,(t=>{i[e.itemKey]=t,this.renderItem(i,o)}))}this.destroyOldChildrens(s)}renderItem(e,t){if(!this.ast.childrens?.length)return;let s=this.node?.childrens?.[t];if(s){if(this.checkObEqual(e,s.ob))return;c(e,((e,t)=>{s.ob[e]!==t&&(s.ob[e]=t)}))}else new Ne(this.ast,e,this.node,this.ext)}destroyOldChildrens(e){for(;this.node.childrens.length>e;){let e=this.node.childrens.pop();if(!e)break;e[X.PARSERKEY]?.destroy(!1)}}checkObEqual(e,t){let s=!0;return void 0!==t&&(c(e,((e,n)=>{t?.[e]!==n&&(s=!1)})),s)}}class Ne extends ye{parser(){this.node=new X.ListItem(this.ob,this.parent),this.appendNode(),this.ast.childrens&&this.ext.parserNodes(this.ast.childrens,this.node,this.ob)}}function we(e,t){if(!e)return e;if(e instanceof Promise)return e.then((e=>Promise.resolve(e)));if(Array.isArray(e)&&e.length){let s=[];for(let n in e){let i,r=e[n];i=t?we(r,t):r,i instanceof Promise&&s.push(i.then((t=>{e[n]=t})))}if(s.length>0)return Promise.all(s).then((()=>Promise.resolve(e)))}else if("object"==typeof e&&null!==e&&u(e)&&e instanceof Element==!1){let s=[];for(let n in e){let i=e[n];if(i instanceof Promise)s.push(i.then((t=>{e[n]=t})));else if(t){let e=we(i,t);e instanceof Promise&&s.push(e)}}if(s.length)return Promise.all(s).then((()=>e))}return e}function Re(e,t){if(!e.constructor)return!1;let s=Object.getOwnPropertyDescriptor(e.constructor.prototype,t);return s&&s.get}class $e extends ye{parser(){if(g(this.ast.cmdName))throw C.error("模板指令","解析AST转换VNode时发生错误,未找到指令名称",this.ast),new Error("解析AST转换VNode时发生错误,未找到指令名称");let e;if("Html"===this.ast.cmdName||"Text"===this.ast.cmdName?e=this.ast.param:this.ast.cmdName.startsWith(fe+".")?e=`${this.ast.cmdName}(${this.ast.param})`:this.ast.cmdName in this.ob&&"function"==typeof this.ob[this.ast.cmdName]&&(e=`${t(this.ast.cmdName)}(${this.ast.param})`),e){let t=this.runExpressWithWatcher(`[${e}]`,this.ob,(t=>{let s=we(t[0]);s instanceof Promise?s.then((e=>{this.changeValue(e)})).catch((t=>{C.error("表达式编译",`${e}异步处理失败`,t)})):this.changeValue(s)}));t||=[];let s=we(t[0]);return s instanceof Promise?("Html"===this.ast.cmdName?this.node=new X.Html("",this.parent,t[1]):this.node=new X.Text("",this.parent),s.then((e=>{this.changeValue(e)})).catch((t=>{C.error("表达式编译",`${e}异步处理失败`,t)}))):"Html"===this.ast.cmdName?this.node=new X.Html(Ae(s),this.parent,t[1]):this.node=new X.Text(Ae(s),this.parent),void this.appendNode()}throw new Error(`未找到命令:${this.ast.cmdName}`)}changeValue(e){this.node&&(this.node instanceof X.Html?this.node.html=Ae(e):this.node.text=Ae(e),this.ext.render?.updateNode(this.node))}}function Ae(e){return null==e||"function"==typeof e?"":e.toString()}const Ce="default";class Oe extends ye{parser(){let e=this.transformParam();this.node=new X.RenderSection(e.id,this.parent),this.node.params=e.params,this.node.section??=this.ob.$sections?.[e.id],this.appendNode(),this.node.section&&(this.node.section.params?(this.node.ob=Object.create(this.node.section.ob||this.ob),this.node.section.params?.forEach(((e,t)=>{V(this.node.ob,e,this.node.params[t])}))):this.node.ob=this.node.section.ob||this.ob,(this.node.section.parser||this.ext).parserNodes(this.node.section.asts,this.node,this.node.ob))}transformParam(){if(this.ast.param){let e=this.runExpressWithWatcher(`[${this.ast.param}]`,this.ob,(e=>{let t=e[0]||Ce;if("string"==typeof t&&t!==this.node.id)throw new Error("section id 不可动态变更");this.node.params=e.slice(1),this.node?.ob&&this.node.section&&this.node.section.params?.forEach(((e,t)=>{this.node?.ob&&this.node.ob[e]!==this.node.params[t]&&(this.node.ob[e]=this.node.params[t])}))}));return{id:e[0]||Ce,params:e.slice(1)}}return{id:Ce,params:[]}}}const xe="组件解析";class Se extends ye{parser(){if(this.ast.node)return this.node=this.ast.node,this.node.parent=this.parent,this.initPropData(),this.appendNode(),void this.node.component?.$mount(this.node);this.node=new X.Component(this.parent),this.initPropData(),this.initEvent(),this.appendNode(),this.renderChildren()}get canReload(){return"tagName"in this.ast||"function"==typeof this.ast.component}reload(){this.canReload?(this.beforeDestroy(),this.renderChildren()):C.warn(xe,"当前组件无法实现reload",this.node)}initPropData(){for(let e of this.ast.attributes)if("ref"!==e.name)if("keep-alive"===e.name&&"false"!==e.value&&(this.node.keepalive=!0),e.express){let t=this.runExpressWithWatcher(e.express,this.ob,(t=>{let s=we(t);s instanceof Promise?s.then((t=>{this.node&&(this.node.propValues[e.name]=t,this.notifyNodeWatcher("update",e.name))})).catch((t=>{C.error(xe,`${e.express}异步处理失败`,t)})):(this.node.propValues[e.name]=s,this.notifyNodeWatcher("update",e.name))})),s=we(t);s instanceof Promise?(this.node.propValues[e.name]=void 0,s.then((t=>{this.node&&(this.node.propValues[e.name]=t)})).catch((t=>{C.error(xe,`${e.express}异步处理失败`,t)}))):this.node.propValues[e.name]=s}else this.node.propValues[e.name]=e.value;else{if(g(e.value)){C.warn(xe,"元素的ref值不可以为空");continue}this.ref=e.value,this.ext.addRef(e.value,this.node)}this.node.propValues=W(this.node.propValues)}initEvent(){this.ast.events.forEach((e=>{let t=e.functionName?this.ob[e.functionName]:void 0;void 0===e.functionName?this.node.events.push([e.name,{modifiers:e.modifiers,callBack:N}]):t&&"function"==typeof t?this.node.events.push([e.name,{modifiers:e.modifiers,callBack:s=>{let n=[];e.functionParam&&(n=this.runExpress(`[${e.functionParam}]`,this.ob)),t.call(this.ext.ob,s,...n)}}]):C.error(xe,`${"tagName"in this.ast?this.ast.tagName:""}元素中${e.name}事件所指定的回调(${e.functionName})方法未找到,请检查`)}))}async renderChildren(){if("tagName"in this.ast){let e=this.ob.components[this.ast.tagName]||Ze(this.ast.tagName);if(void 0===e)return void C.error(xe,`渲染组件失败,未找到名称为'${this.ast.tagName}'的私有组件/全局组件`);if(Je in e||(e=(await e()).default),!this.node)return;{let t=this.getSections();this.node.name=this.ast.tagName,this.node.component=new e(this.node?.propValues,t,this.node?.keepalive)}}else if("function"==typeof this.ast.component){let e=this.getSections();this.node.component=new this.ast.component(this.node?.propValues,e,this.node?.keepalive)}else this.node.component=this.ast.component;if(!this.node)return;if(!this.node.name&&"name"in this.node.component&&this.node.component.name&&"string"==typeof this.node.component.name&&(this.node.name=this.node.component.name),this.node.component.$mount(this.node),!this.node)return;let e=this.node?.component;e.isKeepAlive&&(this.ast.node=this.node)}getSections(){let t={},n=[];return this.ast.childrens.forEach((t=>{if(t.type===s.NodeType.COMMAND&&"if"===t.cmdName&&t.childrens){let i=t,r=t.childrens.some((e=>e.type===s.NodeType.COMMAND&&"section"===e.cmdName)),o=i.condition.startsWith(e+".$sections");if(o){return this.runExpress(i.condition,this.ob)?void n.push(...t.childrens):void 0}if(r&&"if"===i.kind&&!o)return void C.warn(xe,"在解析section时,发现该section包裹在一个条件语句中,该条件语句仅支持以$sections进行if判断,已作排出")}n.push(t)})),n.forEach((e=>{if(e.type===s.NodeType.COMMAND&&"section"===e.cmdName){let s=e,n=s.id||Ce;/^(\'|\")(.*?)((\'|\"))$/.test(n)&&(n=n.slice(1,-1)),t[n]=t[n]||{asts:[],ob:this.ob,params:s.paramKeys,parser:this.ext},t[n].asts.push(...e.childrens||[])}else t[Ce]=t[Ce]||{asts:[],ob:this.ob,parser:this.ext},t[Ce].asts.push(e)})),t}beforeDestroy(e){!0===e&&this.node?.component?.isKeepAlive?this.node?.component?.$destroy():(this.node?.component?.$destroy(!0),this.ast.node=void 0)}}const Pe="Element解析";class Te extends ye{parser(){this.node=new X.Element(this.ast.tagName,this.parent),this.initAttributes(),this.initEvents(),this.appendNode(),this.ext.parserNodes(this.ast.childrens,this.node,this.ob)}initAttributes(){for(let e of this.ast.attributes)if("ref"!==e.name)if(e.express){let t=this.runExpressWithWatcher(e.express,this.ob,(t=>{let s=t=>{this.node&&(this.node.attributes[e.name]=this.transformAttrVal(t),this.ext.render?.updateNode(this.node,e.name),this.notifyNodeWatcher("update",e.name))},n=we(t);n instanceof Promise?n.then((e=>{s(e)})).catch((t=>{C.error(Pe,`${e.express}异步处理失败`,t)})):s(n)})),s=we(t);s instanceof Promise?s.then((t=>{this.node&&(this.node.attributes[e.name]=this.transformAttrVal(t),this.ext.render?.updateNode(this.node,e.name))})).catch((t=>{C.error(Pe,`${e.express}异步处理失败`,t)})):this.node.attributes[e.name]=this.transformAttrVal(s)}else this.node.attributes[e.name]=e.value;else{if(g(e.value)){C.warn(Pe,"元素的ref值不可以为空");continue}this.ref=e.value,this.ext.addRef(e.value,this.node)}}initEvents(){for(let e of this.ast.events){let t=e.functionName?this.ob[e.functionName]:void 0;if(!(void 0===e.functionName||t&&"function"==typeof t))throw new Error(`${this.ast.tagName}元素中${e.name}事件所指定的回调(${e.functionName})方法未找到,请检查`);this.node?.events.push([e.name,{modifiers:e.modifiers,callBack:s=>{if(void 0===t)return;let n=[];e.functionParam&&(n=this.runExpress(`[${e.functionParam}]`,this.ob)),t&&t.call(this.ext.ob,s,...n)}}])}}transformAttrVal(e){return void 0!==e&&("string"==typeof e||"boolean"==typeof e||"function"!=typeof e&&Object.prototype.toString()?e:void 0)}}class De{asts;ob;root=new X.Root;refs={};sleeped=!1;nodeWatcherEvents={};render;constructor(e,t,s){this.asts=e,this.ob=t,this.root.component=t,this.render=G.get(U.IRENDERIOCTAGID)??new U.DomRender,s&&s instanceof X.Node&&(this.root.parent=s,s.childrens??=[],s.childrens.push(this.root))}parser(){this.parserNodes(this.asts,this.root)}mount(e){this.sleeped&&this.weakup(),this.render?.mount(e)}parserNodes(e,t,n){e.forEach((e=>{if(e.type===s.NodeType.TEXT)new Ee(e,n??this.ob,t,this);else if(e.type===s.NodeType.COMMENT)new ve(e,n??this.ob,t,this);else if(e.type===s.NodeType.COMPONENT)new Se(e,n??this.ob,t,this);else if(e.type===s.NodeType.ELEMENT){let s=e;!function(e,t){return!!t.components[e]||!!Ze(e)}(s.tagName,n??this.ob)?new Te(s,n??this.ob,t,this):new Se(s,n??this.ob,t,this)}else if(e.type===s.NodeType.COMMAND){let s=e;switch(s.cmdName){case"if":case"elseif":case"else":new ge(s,n??this.ob,t,this);break;case"for":new be(s,n??this.ob,t,this);break;case"RenderSection":new Oe(s,n??this.ob,t,this);break;case"section":break;default:new $e(s,n??this.ob,t,this)}}}))}addRef(e,t){this.refs[e]=this.refs[e]||[],this.refs[e].push(t)}removeRef(e){for(let t in this.refs)this.refs[t].includes(e)&&y(this.refs[t],e)}addNodeWatcher(e,t){this.nodeWatcherEvents[e]=this.nodeWatcherEvents[e]||[],this.nodeWatcherEvents[e].push(t)}removeNodeWatcher(e,t){y(this.nodeWatcherEvents[e]||[],t)}notifyNodeWatcher(e,t,s,n){this.nodeWatcherEvents[e]?.forEach((e=>{e(t,s,n)}))}sleep(e){let t=e||this.root;t.childrens?.forEach((e=>{let t=()=>{e.childrens&&this.sleep(e),e.sleep=!0,this.render?.removeNode(e,!0)};this.nodeTransition(e,"leave",void 0,(()=>{t()}))||t()})),void 0===e&&(this.sleeped=!0)}weakup(e){let t=e||this.root;t.childrens?.forEach((e=>{e.sleep=!1,this.render?.appendNode(e),e.childrens&&this.weakup(e),this.nodeTransition(e,"enter")})),void 0===e&&(this.sleeped=!1)}destroy(e){for(;this.root.childrens.length;){let t=this.root.childrens[0];t[X.PARSERKEY]?t[X.PARSERKEY].destroy(e):y(this.root.childrens,t)}this.render.destroy(),this.refs={},this.root.childrens.length=0,this.nodeWatcherEvents={},this.asts.length=0}destroyWathcers(){for(let e of this.root.childrens)e[X.PARSERKEY]&&e[X.PARSERKEY].destroyWathcers()}reSetAsts(e,t){this.destroy(t),this.render=G.get(U.IRENDERIOCTAGID)??new U.DomRender,this.asts=e}nodeTransition(e,t,s,n,i){if(e&&e.parent?.childrens&&(e instanceof X.Element||e instanceof X.Component)){let r=function(e){if(e instanceof X.Element||e instanceof X.Component){let t=e instanceof X.Element?e.attributes:e.propValues;return{name:t["transition-name"],type:t["transition-type"]}}}(e);if(s??=r?.name,i??=r?.type,!s)return!1;let o=_e(e);if(o)return"enter"===t?this.render.elementToEnter(o,s,i,(()=>{let t=e[X.PARSERKEY];t&&t.ref&&this.notifyNodeWatcher(t.ref,e,"after-enter"),n?.()})):this.render.elementToLeave(o,s,i,(()=>{let t=e[X.PARSERKEY];t&&t.ref&&this.notifyNodeWatcher(t.ref,e,"after-leave"),n?.()})),!0;C.warn("渲染核心","在执行node动画时,发现数据不完备,请检查")}return!1}}function _e(e){if(e instanceof X.Element)return e;if(e.childrens&&e.childrens.length)for(let t of e.childrens)return t instanceof X.Element?t:_e(t)}function ke(e,t,s){if(void 0===t)return;let n=Array.isArray(s)?s:[s];for(let e of n){if(e===Array&&t instanceof Array)return t;if(typeof t===e.name.toLocaleLowerCase())return t}switch(n[0]){case Number:let e=Number(t);if(!1===isNaN(e))return e;break;case String:return String(t)}throw new Error(`props中${e.toString()}的类型不符合约束类型`)}function Ke(e,t,s){let n,i,r;if("symbol"!=typeof t&&(n=b(t)),t in e?i=e[t]:n&&(i=e[n]),s&&(t in s?r=s[t]:n&&n in s&&(r=s[n])),void 0!==r){if(u(r)&&("type"in r||"required"in r||"default"in r||"validate"in r)){let e=r;if(e.required&&void 0===i)throw new Error(`props中key:${t.toString()}是必须项,请检查`);if(e.type&&(i=ke(t,i,e.type)),e.validate&&!1===e.validate(i))throw new Error(`props中key${t.toString()}的值校验错误`);i=i??e.default}else i=We(r)?ke(t,i,r):i??r;return i}return i}function We(e){return!![String,Array,Number,Object,Function,Boolean].includes(e)||e instanceof Array&&We(e[0])}const Ve="组件",Me=Symbol.for("JOKER_PROPS_DATA_KEY"),Le=Symbol.for("JOKER_PROPS_DATA_PROXY"),Ie=Symbol.for("JOKER_PRIVATE_WATCHERS"),je=Symbol.for("JOKER_EVENT_DATA_KEY"),Ye=Symbol.for("JOKER_IS_DESTROY"),He=Symbol.for("JOKER_PARSER_TEMPLATE_TARGET"),Be=Symbol.for("JOKER_SCOPE_ID"),Je=Symbol.for("JOKER_COMPONENT_TAG"),Fe=Symbol();let Ge=["constructor","$mount","$nodeTransition","$destroy","$getRef","$getRefs","$syncProp","$watchNode","$watch","$on","$off","$trigger","$render","created","mounted","beforeDestroy","sleeped","wakeup","destroyed"];class qe{$sections;isKeepAlive;static[Je]=!0;[Be];model={};template;$root;isSleeped=!1;components={};propsOption;[Me]={};[He];[Le];[Ie]=[];[je]=new Map;[Ye]=!1;[Fe]=!1;constructor(e,t={},s){this.$sections=t,this.isKeepAlive=s,this[Me]=e||{}}get props(){if(void 0===this[Le]){let e=this;this[Le]=new Proxy(e[Me],{get:(t,s)=>Ke(e[Me],s,e.propsOption),set(){throw new Error("props 参数不允许变更,只允许单向数据传递")}})}return this[Le]}$mount(e){if(!1===this[Fe]){let e=()=>{let e=[],t=Object.getPrototypeOf(this);for(;null!==t&&t!==Object.prototype;)Object.getOwnPropertyNames(t).forEach((s=>{!1!==Ge.includes(s)||Re(t,s)||"function"!=typeof t[s]||t[s].prototype?.hasOwnProperty("constructor")||e.push(s)})),t=Object.getPrototypeOf(t);return e};for(let t of e())this[t]=this[t].bind(this);this[Fe]=!0}return this.$root=e,this.isKeepAlive&&this.isSleeped?(this.isSleeped=!1,this[He]&&this.$root?(this[He].mount(this.$root),this.wakeup(),this.$trigger("wakeup"),this.$rootVNode&&Ue(this.$rootVNode),this):(C.error(Ve,"当前组件在唤醒时,发现渲染处理程序已被销毁,无法进行唤醒操作",[this,this.$root]),this)):(this.isSleeped=!1,this.model=W(this.model),this.created(),this.$trigger("created"),this.template&&this.$render(),this.mounted(),this.$trigger("mounted"),this)}$nodeTransition(e,t,s,n,i){if("string"==typeof e){let t=this.$getRef(e);if(!t)return void C.error(Ve,`执行节点动画是找不到ref=${e}的节点`);e=t}this[He]?.nodeTransition(e,t,s,n,i)}$destroy(e){if(!e&&this.isKeepAlive)return this[He]?.sleep(),this.isSleeped=!0,this.sleeped(),this.$trigger("sleeped"),void(this.$rootVNode&&Qe(this.$rootVNode));for(let e of this[Ie])e.destroy();this[Ie].length=0,this[He]?.destroyWathcers(),this.beforeDestroy(),this.$trigger("beforeDestroy"),this[He]?.destroy(),this[He]=void 0,this.template&&Array.isArray(this.template)&&(this.template.length=0),this.$trigger("destroy"),this[je].clear(),this.$root=void 0,this.isSleeped=!1,this.$sections={},this[Ye]=!0,this[Le]=void 0,this[Me]={},this.destroyed()}get $refs(){return this[He]?.refs||{}}$getRef(e){return this.$refs[e]?.[0]}$getRefs(e){return this.$refs[e]}$syncProp(e,t,s){"function"==typeof t&&(s=t,t=void 0),t??=e,s??=e=>e,this.model[t]=s(this.props[e]),this.$watch((()=>this.props[e]),(()=>{this.model[t]=s?.(this.props[e])}))}get $rootVNode(){return this[He]?.root}$watchNode(e,t){if(this[He])return this[He]?.addNodeWatcher(e,t),()=>{this[He]?.removeNodeWatcher(e,t)};C.warn(Ve,"该组件还未挂载,不可以进行节点观察监听")}$watch(e,t,s){let n=new F((()=>{if(!this[Ye])return e();for(let e of this[Ie])e.destroy()}),((e,s)=>{this[Ye]||t(e,s)}),void 0,s);return this[Ie].push(n),[n.value,()=>{n.destroy(),y(this[Ie],n)}]}$on(e,t){let s=this[je].get(e);void 0===s&&(s=[],this[je].set(e,s)),!1===s?.includes(t)&&s.push(t)}$off(e,t){let s=this[je].get(e);s&&(t?y(s,t):s.length=0)}$trigger(e,t,s){if(!this.$root)return;let n={eventName:e,stopPropagation:s?.stopPropagation??(()=>{}),preventDefault:s?.preventDefault??(()=>{}),data:t,target:s?.target??this.$rootVNode,event:s?.event};if(this.$rootVNode&&this.$rootVNode.parent&&this.$rootVNode.parent instanceof X.Component&&!1===this[He]?.render.triggerEvent(this.$rootVNode.parent,e,n))return;let i=this[je].get(e);i?.length&&[...i].forEach((e=>{e(n)}));let r=this[je].get("*");r?.length&&[...r].forEach((e=>{e(n)}))}$render(e,t){e??=this.template,this.template="function"==typeof e?e(n):e,this.$root&&(this.template??=[],this[He]?.reSetAsts(this.template,t),this[He]??=new De(this.template,this,this.$root),this[He].parser(),this[He].mount(this.$root))}created(){}mounted(){}beforeDestroy(){}sleeped(){}wakeup(){}destroyed(){}}const Xe={};function ze(e,t){if("string"==typeof e)t&&(Xe[e]=t);else for(let t in e)Xe[t]=e[t]}function Ze(e){return Xe[e]}function Qe(e){e.childrens?.forEach((e=>{e instanceof X.Component&&e.component?.sleeped(),Qe(e)}))}function Ue(e){e.childrens?.forEach((e=>{e instanceof X.Component&&e.component?.wakeup(),Ue(e)}))}class et extends qe{template=[];cache=new Map;mounted(){this.$watch((()=>this.props.name),(async e=>{this.$render([],!0),await Promise.resolve(),this.$root&&this.loadComponent(e)})),this.loadComponent(this.props.name)}propsVaule;created(){this.initProps()}initProps(){let e={};this.props.props||(Object.keys(this.props).forEach((t=>{!1!==this.filterProps(t)&&(e[t]=this.props[t],this.$watch((()=>this.props[t]),(()=>{this.propsVaule[t]=this.props[t]})))})),this.propsVaule=W(e))}filterProps(e){if("string"!=typeof e)return!1;let t=b(e);return"transition-name"!==t&&"name"!==t&&"keep-alive"!==t&&"ref"!==t&&void 0}async loadComponent(e){if(!e)return void this.$render([],this.isKeepAlive);let t;if(this.isKeepAlive){let t=this.cache.get(e);if(t)return void this.$render([i(t,{"transition-name":this.props["transition-name"]})],!0)}let s=this.$rootVNode?.parent?.[X.PARSERKEY]?.ob.components,n=s?.[e];void 0===n&&(n=Ze(e)),n?(Je in n||(n=(await n()).default),t=new n(this.props.props||this.propsVaule,this.$sections,this.isKeepAlive),t.$on("*",(e=>{this.$trigger(e.eventName,e.data,e)})),this.isKeepAlive&&this.cache.set(e,t),this.$render([i(t,{"transition-name":this.props["transition-name"]})],this.isKeepAlive)):C.warn("component",`未找到${e}的组件`)}beforeDestroy(){this.removeCache()}removeCache(e){if(e){let t=this.cache.get(e);this.cache.delete(e),t&&t.$destroy(!0)}else this.cache.forEach((e=>{e.$destroy(!0)})),this.cache.clear()}}class tt extends qe{template=function(){return[r("RenderSection")]}}ze({template:tt,component:et});class st{eventDatas=new Map;on(e,t){let s=this.eventDatas.get(e);void 0===s&&(s=[],this.eventDatas.set(e,s));let n={callBack:t};return s.push(n),()=>{s&&y(s,n)}}once(e,t){let s=this.eventDatas.get(e);void 0===s&&(s=[],this.eventDatas.set(e,s));let n={callBack:t,once:!0};return s.push(n),()=>{s&&y(s,n)}}off(e,t){if(void 0!==e)if(t){let s=this.eventDatas.get(e),n=s?.find((e=>e.callBack===t));n&&y(s,n)}else this.eventDatas.delete(e);else this.eventDatas.clear()}async trigger(e,t){let s=[...this.eventDatas.get(e)||[]];if(s.push(...this.eventDatas.get("*")||[]),s&&s.length){let n=0,i=0,r=!1;for(;s[n];){let o=s[n],a=await o.callBack({stopPropagation:()=>r=!0,callTimes:i,eventName:e},t);if(o.once?y(s,o):n++,!1===a||r)return!1}}}}export{qe as Component,et as ComponentContainer,S as Dep,st as EventBus,G as IContainer,Je as JOKER_COMPONENT_TAG,q as JOKER_VNODE_TAG,P as OBJECTPROXY_DEPID,He as PARSER_TEMPLATE_TARGET,De as ParserTemplate,U as Render,Be as SCOPE_ID,L as ShallowObserver,tt as Template,X as VNode,F as Watcher,ce as __GLONAL_FUNTIONS__,d as __JOKER_HMR_RUNTIME,H as combinedReply,V as defineObserverProperty,Ze as getGlobalComponent,B as isObserverData,W as observer,ze as registerGlobalComponent,ue as registerGlobalFunction};
|