@cloudbase/lowcode-builder 1.8.106 → 1.8.108
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/lib/builder/config/dependencies.d.ts +10 -0
- package/lib/builder/config/dependencies.js +46 -0
- package/lib/builder/config/index.d.ts +1 -0
- package/lib/builder/config/index.js +5 -3
- package/lib/builder/core/index.d.ts +1 -1
- package/lib/builder/core/index.js +13 -13
- package/lib/builder/h5/generate.js +1 -0
- package/lib/builder/mp/BuildContext.d.ts +1 -0
- package/lib/builder/mp/index.d.ts +1 -2
- package/lib/builder/mp/index.js +13 -38
- package/lib/builder/mp/lowcode.js +5 -1
- package/lib/builder/mp/materials.d.ts +2 -3
- package/lib/builder/mp/materials.js +28 -26
- package/lib/builder/mp/mp_config.js +2 -1
- package/lib/builder/mp/util.d.ts +5 -2
- package/lib/builder/mp/util.js +14 -6
- package/lib/builder/mp/wxml.d.ts +3 -1
- package/lib/builder/mp/wxml.js +20 -7
- package/lib/builder.web.js +8 -8
- package/package.json +4 -4
- package/template/html/index.html.ejs +4 -2
- package/template/mp/app/common.js +0 -2
- package/template/mp/app/weapps-api.js +1 -20
- package/template/mp/common/info/index.js +4 -2
- package/template/mp/common/util.js +33 -774
- package/template/mp/common/weapp-page.js +12 -514
- package/template/mp/component/index.js +52 -19
- package/template/mp/component/index.json +1 -1
- package/template/mp/datasources/index.js.tpl +3 -99
- package/template/mp/package.json +4 -15
- package/template/mp/packages/$wd_system/pages/login/index.json +1 -1
- package/template/mp/packages/$wd_system/pages/login/methods/loginByWXPhone.js +6 -3
- package/template/mp/page/index.js +1 -2
- package/template/mp/common/constant.js +0 -1
- package/template/mp/common/data-patch-test.js +0 -60
- package/template/mp/common/data-patch.js +0 -66
- package/template/mp/common/event-emitter.js +0 -124
- package/template/mp/common/flow.js +0 -65
- package/template/mp/common/merge-renderer.js +0 -75
- package/template/mp/common/placeholder/index.js +0 -1
- package/template/mp/common/placeholder/index.json +0 -4
- package/template/mp/common/placeholder/index.wxml +0 -1
- package/template/mp/common/placeholder/index.wxss +0 -1
- package/template/mp/common/query.js +0 -300
- package/template/mp/common/style.js +0 -34
- package/template/mp/common/watch.js +0 -70
- package/template/mp/common/weapp-component.js +0 -289
- package/template/mp/common/widget.js +0 -872
|
@@ -1,872 +0,0 @@
|
|
|
1
|
-
import { observable, autorun, untracked } from 'mobx';
|
|
2
|
-
import { styleToCss } from './style';
|
|
3
|
-
import { getDeep, generateDataContext, processStaticResourceAttribute } from './util';
|
|
4
|
-
import { compLowcodes } from './weapp-component';
|
|
5
|
-
import EventEmitter from './event-emitter';
|
|
6
|
-
import lodashSet from 'lodash.set';
|
|
7
|
-
import { REPEATER } from './constant';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* convert widget prop to data for wxml
|
|
11
|
-
* @param {*} props
|
|
12
|
-
*/
|
|
13
|
-
const EXTRA_PROPS_MAP = [
|
|
14
|
-
/**
|
|
15
|
-
* create widgets
|
|
16
|
-
*/
|
|
17
|
-
'id',
|
|
18
|
-
'widgetType',
|
|
19
|
-
'parent',
|
|
20
|
-
'children',
|
|
21
|
-
'_scope',
|
|
22
|
-
'_disposers',
|
|
23
|
-
'_eventListeners',
|
|
24
|
-
/**
|
|
25
|
-
* mount widget api
|
|
26
|
-
*/
|
|
27
|
-
'findWidgets',
|
|
28
|
-
'getWidgetsByType',
|
|
29
|
-
'getOwnerWidget',
|
|
30
|
-
'getDom',
|
|
31
|
-
'on',
|
|
32
|
-
'off',
|
|
33
|
-
'getConfig',
|
|
34
|
-
'_getInstanceRef',
|
|
35
|
-
'_instanceRef',
|
|
36
|
-
'_methods',
|
|
37
|
-
'_userWidget',
|
|
38
|
-
/**
|
|
39
|
-
* 其他挂载
|
|
40
|
-
*/
|
|
41
|
-
'_descendants',
|
|
42
|
-
'_forContext', // for root 挂载
|
|
43
|
-
/**
|
|
44
|
-
* widgetProps 附带值
|
|
45
|
-
*/
|
|
46
|
-
'_order',
|
|
47
|
-
'_staticResourceAttribute',
|
|
48
|
-
'classList',
|
|
49
|
-
].reduce((map, key) => {
|
|
50
|
-
map[key] = true;
|
|
51
|
-
return map;
|
|
52
|
-
}, {});
|
|
53
|
-
|
|
54
|
-
function resolveWidgetProp(props, widgetId) {
|
|
55
|
-
let { classList = [], _staticResourceAttribute = ['src'], ...restProps } = props;
|
|
56
|
-
const data = {};
|
|
57
|
-
Object.keys(restProps).forEach((key) => {
|
|
58
|
-
if (EXTRA_PROPS_MAP[key]) {
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
if (restProps[key] instanceof Function || restProps[key] === undefined) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
data[key] = restProps[key];
|
|
65
|
-
});
|
|
66
|
-
data.style = styleToCss(restProps.style);
|
|
67
|
-
data.className = `${widgetId ? `wd-comp-id-${widgetId}` : ''} ${classList.join ? classList.join(' ') : classList}`;
|
|
68
|
-
|
|
69
|
-
_staticResourceAttribute?.forEach?.((property) => {
|
|
70
|
-
processStaticResourceAttribute(data, undefined, property);
|
|
71
|
-
});
|
|
72
|
-
return data;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// widget prop -> wxml data
|
|
76
|
-
export function resolveWidgetData(props, widgetId) {
|
|
77
|
-
if (!Array.isArray(props)) {
|
|
78
|
-
return resolveWidgetProp(props, widgetId);
|
|
79
|
-
}
|
|
80
|
-
return props.map((prop) => resolveWidgetData(prop, widgetId));
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function createWidgets(widgetProps, dataBinds, ownerMpInst, widgetHolder) {
|
|
84
|
-
const rootNode = createWidgetDataTree(widgetProps, dataBinds);
|
|
85
|
-
const failedBinds = [];
|
|
86
|
-
const result = createSubWidgetTree(
|
|
87
|
-
{ ownerForWidgetHolder: {} },
|
|
88
|
-
rootNode,
|
|
89
|
-
dataBinds,
|
|
90
|
-
ownerMpInst,
|
|
91
|
-
{},
|
|
92
|
-
failedBinds,
|
|
93
|
-
undefined,
|
|
94
|
-
widgetHolder,
|
|
95
|
-
);
|
|
96
|
-
retryFailedBinds(failedBinds, true);
|
|
97
|
-
return result;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* @param ownerMpInst The MP page or component instance the widgets belongs to
|
|
102
|
-
* @param ownerForWidgetHolder null for the virtual root node(first run)
|
|
103
|
-
* @param curForNode a component node or a virtual root tree node
|
|
104
|
-
* @returns {widgets: {id1:[], id2}, rootWidget: {children: [], _disposers: [], ...otherProps}}
|
|
105
|
-
*/
|
|
106
|
-
function createSubWidgetTree(
|
|
107
|
-
ctx,
|
|
108
|
-
curForNode,
|
|
109
|
-
dataBinds,
|
|
110
|
-
ownerMpInst,
|
|
111
|
-
forContext = {},
|
|
112
|
-
failedBinds = [],
|
|
113
|
-
parentWidget = { children: observable([]), _disposers: [] },
|
|
114
|
-
widgetHolder = {},
|
|
115
|
-
) {
|
|
116
|
-
const { ownerForWidgetHolder = {}, existingWidgetMap = {} } = ctx;
|
|
117
|
-
/**
|
|
118
|
-
* 不能类似web实现记录额外的 _disposers
|
|
119
|
-
* const widgetHolder = { _disposers: [] }
|
|
120
|
-
* 因为 merger-render.initMergeRenderer 里面没有特殊处理
|
|
121
|
-
* 因为 构建 widgets 过程中对 $page.widgets 进行了访问,需要使用副作用的方式,保持 $page.widgets 引用
|
|
122
|
-
*/
|
|
123
|
-
// const widgetHolder = {};
|
|
124
|
-
const { lists: forLists = [] } = forContext;
|
|
125
|
-
const currentIndex = forLists[0]?.currentIndex;
|
|
126
|
-
const indexPostfix = (forContext.lists || [])
|
|
127
|
-
.slice()
|
|
128
|
-
.reverse()
|
|
129
|
-
.map(({ currentIndex }) => ID_SEPARATOR + currentIndex)
|
|
130
|
-
.join('');
|
|
131
|
-
|
|
132
|
-
// traverse down the tree to set up all widgets
|
|
133
|
-
dfsTree(
|
|
134
|
-
curForNode,
|
|
135
|
-
(node, parentNode, cache) => {
|
|
136
|
-
const parentForWidgetArr = ownerForWidgetHolder[node.id] || [];
|
|
137
|
-
const { _waForKey } = node.value;
|
|
138
|
-
|
|
139
|
-
const key = forContext.forItems?.[node.id]?.[_waForKey] || currentIndex;
|
|
140
|
-
let forExistingWidgetMap = {};
|
|
141
|
-
let forExsitWidget;
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* for 起始节点,根据 existingWidgetMap 判断复用
|
|
145
|
-
*/
|
|
146
|
-
if (node.id === curForNode.id) {
|
|
147
|
-
if (existingWidgetMap[key] && existingWidgetMap[key].index === currentIndex) {
|
|
148
|
-
forExistingWidgetMap = existingWidgetMap[key].widgets || {};
|
|
149
|
-
forExsitWidget = forExistingWidgetMap[node.id];
|
|
150
|
-
if (forExsitWidget) {
|
|
151
|
-
cache[node.id] = {
|
|
152
|
-
widgets: forExistingWidgetMap,
|
|
153
|
-
};
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
} else if (cache[parentNode?.id]) {
|
|
157
|
-
forExsitWidget = cache[parentNode?.id].widgets[node.id] || null;
|
|
158
|
-
if (forExsitWidget) {
|
|
159
|
-
cache[node.id] = cache[parentNode?.id];
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
const existedWidget = forExsitWidget || null;
|
|
163
|
-
|
|
164
|
-
if (node.forCount === curForNode.forCount) {
|
|
165
|
-
/**
|
|
166
|
-
* 同一层循环作用域内,当前节点与 curForNode(循环根节点)在同一级循环作用域中
|
|
167
|
-
* 即没有再开辟新级别的 for 循环
|
|
168
|
-
* Leaf node
|
|
169
|
-
*/
|
|
170
|
-
let w = existedWidget;
|
|
171
|
-
if (!existedWidget) {
|
|
172
|
-
const parentNode = node.parent;
|
|
173
|
-
let parent = parentNode ? widgetHolder[parentNode.id] || ownerForWidgetHolder[parentNode.id] : null;
|
|
174
|
-
w = createWidget(node.value, node.id, indexPostfix, parent, ownerMpInst, forContext.forItems?.[node.id]);
|
|
175
|
-
w._key = key;
|
|
176
|
-
|
|
177
|
-
if (!parent) {
|
|
178
|
-
parentWidget.children.push(w);
|
|
179
|
-
}
|
|
180
|
-
} else {
|
|
181
|
-
w.id = `${node.id}${indexPostfix}`;
|
|
182
|
-
disposeWidget(existedWidget, true);
|
|
183
|
-
}
|
|
184
|
-
parentForWidgetArr[currentIndex || 0] = w;
|
|
185
|
-
setUpWidgetDataBinds(w, dataBinds[node.id], forContext, failedBinds, ownerMpInst._getInstance());
|
|
186
|
-
widgetHolder[node.id] = w;
|
|
187
|
-
if (widgetHolder?.[node._ancestorId]) {
|
|
188
|
-
// 在虚拟项 RepeaterItem 下挂载所有的子孙 __descendants
|
|
189
|
-
// 这里不要用 lodashSet,否则会出现刷新几次,出现 Error: [mobx.array] Index out of bounds 的错误,原因暂不明
|
|
190
|
-
widgetHolder[node._ancestorId]._descendants = widgetHolder[node._ancestorId]._descendants || {};
|
|
191
|
-
widgetHolder[node._ancestorId]._descendants[node.id] = widgetHolder[node.id];
|
|
192
|
-
}
|
|
193
|
-
} else {
|
|
194
|
-
if (!existedWidget) {
|
|
195
|
-
widgetHolder[node.id] = observable([]);
|
|
196
|
-
} else {
|
|
197
|
-
// Reuse existed for widget array
|
|
198
|
-
widgetHolder[node.id] = existedWidget;
|
|
199
|
-
}
|
|
200
|
-
if (parentForWidgetArr) {
|
|
201
|
-
parentForWidgetArr[currentIndex || 0] = widgetHolder[node.id];
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
},
|
|
205
|
-
undefined,
|
|
206
|
-
);
|
|
207
|
-
|
|
208
|
-
// run for of next level
|
|
209
|
-
dfsTree(
|
|
210
|
-
curForNode,
|
|
211
|
-
(node) => {
|
|
212
|
-
if (node.forCount === curForNode.forCount + 1 && dataBinds[node.id] && dataBinds[node.id]._waFor) {
|
|
213
|
-
// find the node bound with next level for
|
|
214
|
-
const parent = getNodeParentWidget(node, widgetHolder, parentWidget);
|
|
215
|
-
const dispose = runFor(node, dataBinds, ownerMpInst, forContext, widgetHolder, failedBinds, parent);
|
|
216
|
-
parent._disposers.push(dispose); // Add the for bind dispose to the parent node of forNode
|
|
217
|
-
}
|
|
218
|
-
},
|
|
219
|
-
undefined,
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
retryFailedBinds(failedBinds);
|
|
223
|
-
|
|
224
|
-
return { widgets: widgetHolder, rootWidget: widgetHolder[curForNode.id] || parentWidget };
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Retry failed databinds
|
|
228
|
-
function retryFailedBinds(failedBinds, finalTry) {
|
|
229
|
-
const len = failedBinds.length;
|
|
230
|
-
for (let i = 0; i < len; i++) {
|
|
231
|
-
const setUpDataBind = failedBinds.shift();
|
|
232
|
-
setUpDataBind(finalTry);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
*
|
|
238
|
-
* @param {*} curForNode
|
|
239
|
-
* @param {*} forContext
|
|
240
|
-
* @param {*} parentForWidgets
|
|
241
|
-
* @param {*} parentWidget
|
|
242
|
-
* @returns top level widgets or for dispose
|
|
243
|
-
*/
|
|
244
|
-
const _FOR_ERROR_CACHE_MAP = {};
|
|
245
|
-
function runFor(curForNode, dataBinds, ownerMpInst, forContext, ownerForWidgetHolder, failedBinds, parentWidget) {
|
|
246
|
-
const nodeId = curForNode.id;
|
|
247
|
-
const { _waForKey } = curForNode.value;
|
|
248
|
-
|
|
249
|
-
const dispose = autorun(() => {
|
|
250
|
-
let forList = [];
|
|
251
|
-
try {
|
|
252
|
-
clearTimeout(_FOR_ERROR_CACHE_MAP[nodeId]);
|
|
253
|
-
|
|
254
|
-
const $instance = ownerMpInst._getInstance();
|
|
255
|
-
const dataContext = untracked(() => generateDataContext(parentWidget));
|
|
256
|
-
const $w = untracked(() => generateWidgetAPIContext($instance?.__internal__?.$w, parentWidget, forContext));
|
|
257
|
-
|
|
258
|
-
forList = dataBinds[nodeId]._waFor.call(
|
|
259
|
-
$instance,
|
|
260
|
-
$instance,
|
|
261
|
-
forContext.lists,
|
|
262
|
-
forContext.forItems,
|
|
263
|
-
undefined,
|
|
264
|
-
dataContext,
|
|
265
|
-
$w,
|
|
266
|
-
);
|
|
267
|
-
if (!Array.isArray(forList)) {
|
|
268
|
-
forList = [];
|
|
269
|
-
}
|
|
270
|
-
} catch (e) {
|
|
271
|
-
forList = [];
|
|
272
|
-
_FOR_ERROR_CACHE_MAP[nodeId] = setTimeout(() => {
|
|
273
|
-
console.warn('For binding error', nodeId, e);
|
|
274
|
-
}, 1000);
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
// Track list change (e.g. push)
|
|
278
|
-
forList.forEach((e) => {});
|
|
279
|
-
|
|
280
|
-
untracked(() => {
|
|
281
|
-
// dispose widgets before reused instead
|
|
282
|
-
// disposeWidgets(parentForWidgets[curForNode.id])
|
|
283
|
-
const exsitMap = forList.reduce((map, item, index) => {
|
|
284
|
-
const cache = item?.[_waForKey] || index;
|
|
285
|
-
if (cache !== undefined && map[cache] === undefined) {
|
|
286
|
-
map[cache] = index;
|
|
287
|
-
}
|
|
288
|
-
return map;
|
|
289
|
-
}, {});
|
|
290
|
-
const forWidgets = ownerForWidgetHolder[nodeId];
|
|
291
|
-
const existingWidgetMap = {};
|
|
292
|
-
const existingWidgetIndexMap = {};
|
|
293
|
-
const extraWidgetsIndexMap = {};
|
|
294
|
-
forWidgets.forEach((widget, index) => {
|
|
295
|
-
const cecheKey = widget._key || index;
|
|
296
|
-
if (exsitMap[cecheKey] !== undefined) {
|
|
297
|
-
const nodeId = widget.id?.split(ID_SEPARATOR)[0];
|
|
298
|
-
existingWidgetMap[cecheKey] = { index: exsitMap[cecheKey], widgets: { [nodeId]: widget } };
|
|
299
|
-
/**
|
|
300
|
-
* 此处依赖了 existingWidgetMap[cecheKey].widgets 的引用,
|
|
301
|
-
* 为了直接可以通过 index 访问到 existingWidgetMap 里的值进行编辑
|
|
302
|
-
* 但是依赖引用关系,存在维护风险
|
|
303
|
-
*/
|
|
304
|
-
existingWidgetIndexMap[index] = existingWidgetMap[cecheKey].widgets;
|
|
305
|
-
// need to use uqique key
|
|
306
|
-
exsitMap[cecheKey] = undefined;
|
|
307
|
-
} else {
|
|
308
|
-
extraWidgetsIndexMap[index] = widget;
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
// clean extra widgets of previous for run
|
|
313
|
-
dfsTree(
|
|
314
|
-
curForNode,
|
|
315
|
-
(node) => {
|
|
316
|
-
const arr = ownerForWidgetHolder[node.id] || [];
|
|
317
|
-
/**
|
|
318
|
-
* clone 上次 for 已有的 widgets
|
|
319
|
-
*/
|
|
320
|
-
if (node.id !== curForNode.id) {
|
|
321
|
-
arr.forEach((item, index) => {
|
|
322
|
-
if (existingWidgetIndexMap[index]) {
|
|
323
|
-
existingWidgetIndexMap[index][node.id] = item;
|
|
324
|
-
}
|
|
325
|
-
});
|
|
326
|
-
}
|
|
327
|
-
if (!Object.keys(extraWidgetsIndexMap).length && arr.length === Object.keys(existingWidgetIndexMap).length) {
|
|
328
|
-
/**
|
|
329
|
-
* 数组完全复用,不需要进行修改
|
|
330
|
-
*/
|
|
331
|
-
} else {
|
|
332
|
-
/**
|
|
333
|
-
* 重头开始生成
|
|
334
|
-
* 清空原有 arr 并保持引用不变
|
|
335
|
-
*/
|
|
336
|
-
arr.splice(0, arr.length);
|
|
337
|
-
}
|
|
338
|
-
},
|
|
339
|
-
undefined,
|
|
340
|
-
);
|
|
341
|
-
|
|
342
|
-
/**
|
|
343
|
-
* 明确已经不会复用的节点,清除 mobx observer
|
|
344
|
-
* 并递归清理子节点
|
|
345
|
-
*/
|
|
346
|
-
for (const index in extraWidgetsIndexMap) {
|
|
347
|
-
const w = extraWidgetsIndexMap[index];
|
|
348
|
-
disposeWidget(w);
|
|
349
|
-
const { children } = w.parent || parentWidget;
|
|
350
|
-
children.remove(w);
|
|
351
|
-
// w.parent = null
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
const isInRepeaterChild = isRepeaterWidget(parentWidget, REPEATER.REPEATER_NAME);
|
|
355
|
-
forList.forEach((item, index) => {
|
|
356
|
-
let forContextListAlias;
|
|
357
|
-
let { lists = [], forItems = {} } = forContext;
|
|
358
|
-
const listMeta = { currentItem: item, currentIndex: index };
|
|
359
|
-
if (isInRepeaterChild) {
|
|
360
|
-
forContextListAlias = {
|
|
361
|
-
[`${parentWidget.forIndex}` || 'currentIndex']: listMeta.currentIndex,
|
|
362
|
-
[`${parentWidget.forItem}` || 'currentItem']: listMeta.currentItem,
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
const _forContext = {
|
|
366
|
-
lists: [{ ...listMeta, alias: forContextListAlias }, ...lists],
|
|
367
|
-
forItems: { ...forItems, [nodeId]: item },
|
|
368
|
-
};
|
|
369
|
-
const { rootWidget } = createSubWidgetTree(
|
|
370
|
-
{ ownerForWidgetHolder, existingWidgetMap },
|
|
371
|
-
curForNode,
|
|
372
|
-
dataBinds,
|
|
373
|
-
ownerMpInst,
|
|
374
|
-
_forContext,
|
|
375
|
-
failedBinds,
|
|
376
|
-
parentWidget,
|
|
377
|
-
);
|
|
378
|
-
rootWidget._forContext = _forContext;
|
|
379
|
-
});
|
|
380
|
-
});
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
return dispose;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
export function createWidget(props, nodeId, indexPostfix, parent, ownerMpInst, forContext) {
|
|
387
|
-
const { widgetType, _parentId, ...restProps } = props;
|
|
388
|
-
const w = observable(restProps);
|
|
389
|
-
const id = `${nodeId}${indexPostfix}`;
|
|
390
|
-
|
|
391
|
-
// Builtin props
|
|
392
|
-
w.id = id; // 重用之后要修改id
|
|
393
|
-
// Object.defineProperty(w, 'id', { value: id });
|
|
394
|
-
Object.defineProperty(w, 'widgetType', { value: widgetType });
|
|
395
|
-
Object.defineProperty(w, '_scope', {
|
|
396
|
-
value: observable({
|
|
397
|
-
id: nodeId,
|
|
398
|
-
dataContext: {},
|
|
399
|
-
/**
|
|
400
|
-
* 当前节点的 for currentItem 对象
|
|
401
|
-
*/
|
|
402
|
-
forContext,
|
|
403
|
-
}),
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
// w._disposers = []
|
|
407
|
-
// w.children = [];
|
|
408
|
-
Object.defineProperty(w, 'children', { value: observable([]) });
|
|
409
|
-
Object.defineProperty(w, '_disposers', { value: observable([]) });
|
|
410
|
-
Object.defineProperty(w, '_eventListeners', { value: new EventEmitter() });
|
|
411
|
-
Object.defineProperty(w, '_instanceRef', { value: observable({ current: null }) });
|
|
412
|
-
|
|
413
|
-
if (parent) {
|
|
414
|
-
// w.parent = parent
|
|
415
|
-
Object.defineProperty(w, 'parent', { value: parent });
|
|
416
|
-
parent.children.push(w);
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
mountBuiltinWigetsAPI(w, ownerMpInst);
|
|
420
|
-
|
|
421
|
-
if (isRepeaterWidget(w, REPEATER.REPEATER_NAME)) {
|
|
422
|
-
if (!w.items) {
|
|
423
|
-
Object.defineProperty(w, 'items', {
|
|
424
|
-
get() {
|
|
425
|
-
return (w.children || []).map((item) => {
|
|
426
|
-
const descendants = {};
|
|
427
|
-
Object.keys(item?._descendants || {}).forEach((key) => {
|
|
428
|
-
descendants[key] = item._descendants[key]._userWidget;
|
|
429
|
-
});
|
|
430
|
-
return descendants;
|
|
431
|
-
});
|
|
432
|
-
},
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
// 默认初始值
|
|
436
|
-
w._disposers.push(
|
|
437
|
-
autorun((r) => {
|
|
438
|
-
const ref = {
|
|
439
|
-
data: w.data,
|
|
440
|
-
items: w.items,
|
|
441
|
-
};
|
|
442
|
-
untracked(() => {
|
|
443
|
-
w._instanceRef.current = ref;
|
|
444
|
-
});
|
|
445
|
-
}),
|
|
446
|
-
);
|
|
447
|
-
}
|
|
448
|
-
return w;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
function setUpWidgetDataBinds(w, dataBinds, forContext, failedBinds, ctx) {
|
|
452
|
-
Object.keys(dataBinds || {})
|
|
453
|
-
.sort((a, b) => {
|
|
454
|
-
return a.length - b.length > 0 ? 1 : -1;
|
|
455
|
-
})
|
|
456
|
-
.map((prop) => {
|
|
457
|
-
if (prop === '_waFor') {
|
|
458
|
-
return;
|
|
459
|
-
}
|
|
460
|
-
let timer = null;
|
|
461
|
-
const setUpDataBind = (isFinalTry) => {
|
|
462
|
-
let ran = false;
|
|
463
|
-
const dispose = autorun((reaction) => {
|
|
464
|
-
try {
|
|
465
|
-
clearTimeout(timer);
|
|
466
|
-
|
|
467
|
-
const dataContext = untracked(() => generateDataContext(w));
|
|
468
|
-
const $w = untracked(() => generateWidgetAPIContext(ctx?.__internal__?.$w, w, forContext));
|
|
469
|
-
|
|
470
|
-
// Computed data bind in the next tick since data bind may read widgets data
|
|
471
|
-
const value = dataBinds[prop].call(
|
|
472
|
-
ctx,
|
|
473
|
-
ctx,
|
|
474
|
-
forContext.lists,
|
|
475
|
-
forContext.forItems,
|
|
476
|
-
undefined,
|
|
477
|
-
dataContext,
|
|
478
|
-
$w,
|
|
479
|
-
);
|
|
480
|
-
const paths = prop.split('.').filter((key) => !!key);
|
|
481
|
-
if (paths.length > 1) {
|
|
482
|
-
// 一定要 untracked 不然爆栈了
|
|
483
|
-
untracked(() => lodashSet(w, prop, value));
|
|
484
|
-
} else {
|
|
485
|
-
// 普通 key 直接赋值
|
|
486
|
-
w[prop] = value;
|
|
487
|
-
}
|
|
488
|
-
} catch (e) {
|
|
489
|
-
if (prop === '_waIf') {
|
|
490
|
-
w[prop] = false;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
if (isFinalTry || ran) {
|
|
494
|
-
timer = setTimeout(() => {
|
|
495
|
-
console.warn(`Error computing data bind ${w.id}.${prop}`, e);
|
|
496
|
-
}, 1000);
|
|
497
|
-
} else {
|
|
498
|
-
failedBinds.push((...args) => {
|
|
499
|
-
reaction.dispose();
|
|
500
|
-
return setUpDataBind(...args);
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
ran = true;
|
|
505
|
-
}
|
|
506
|
-
});
|
|
507
|
-
w._disposers.push(dispose);
|
|
508
|
-
};
|
|
509
|
-
setUpDataBind();
|
|
510
|
-
});
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
export function generateForContextOfWidget(widget) {
|
|
514
|
-
const forContext = widget._forContext;
|
|
515
|
-
if (forContext) return forContext;
|
|
516
|
-
if (widget.parent) return generateForContextOfWidget(widget.parent);
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
export const ID_SEPARATOR = '-';
|
|
520
|
-
export function getWidget(widgets, id) {
|
|
521
|
-
return getDeep(widgets, id, ID_SEPARATOR);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
function getNodeParentWidget(node, widgets, defaultParent = { children: observable([]), _disposers: [] }) {
|
|
525
|
-
return (node?.parent?.id && widgets?.[node.parent.id]) || defaultParent;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
/**
|
|
529
|
-
* Add parent, children to widget
|
|
530
|
-
*/
|
|
531
|
-
function createWidgetDataTree(widgets, dataBinds) {
|
|
532
|
-
const virtualRoot = { children: [], forCount: 0 };
|
|
533
|
-
const nodes = Object.keys(widgets).reduce((result, id) => {
|
|
534
|
-
const w = widgets[id];
|
|
535
|
-
result[id] = { id, value: w, _order: w._order, children: [], parent: null, forCount: 0 };
|
|
536
|
-
return result;
|
|
537
|
-
}, {});
|
|
538
|
-
|
|
539
|
-
// Create widgets tree API
|
|
540
|
-
Object.keys(nodes).map((id) => {
|
|
541
|
-
const curNode = nodes[id];
|
|
542
|
-
const parent = nodes[widgets[id]._parentId];
|
|
543
|
-
// delete widgets[id]._parentId
|
|
544
|
-
if (!parent) {
|
|
545
|
-
virtualRoot.children.push(curNode);
|
|
546
|
-
return;
|
|
547
|
-
}
|
|
548
|
-
curNode.parent = parent;
|
|
549
|
-
parent.children.push(curNode);
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
// Sort children
|
|
553
|
-
Object.keys(nodes).map((id) => {
|
|
554
|
-
nodes[id].children.sort((a, b) => a._order - b._order);
|
|
555
|
-
});
|
|
556
|
-
|
|
557
|
-
virtualRoot.children.map(addForCount);
|
|
558
|
-
|
|
559
|
-
// dfs, add forCount
|
|
560
|
-
function addForCount(node) {
|
|
561
|
-
if (node.parent) {
|
|
562
|
-
node.forCount = node.parent.forCount;
|
|
563
|
-
const { widgetType, getConfig } = node.parent.value;
|
|
564
|
-
if (isRepeaterWidget({ widgetType, getConfig }, REPEATER.REPEATER_ITEM_NAME)) {
|
|
565
|
-
node._ancestorId = node.parent.id;
|
|
566
|
-
}
|
|
567
|
-
if (node.parent?._ancestorId) {
|
|
568
|
-
// Repeater 作用域内的所有子孙(排除里面的 Repeater 组件,它本身又产生深一层的作用域)继承父级的循环信息
|
|
569
|
-
if (!node._ancestorId) {
|
|
570
|
-
node._ancestorId = node.parent._ancestorId;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
if (dataBinds[node.id]?._waFor) {
|
|
575
|
-
node.forCount += 1;
|
|
576
|
-
}
|
|
577
|
-
node.children.map(addForCount);
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
return virtualRoot;
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
function dfsTree(node, fn, parent, cache = {}) {
|
|
584
|
-
node.value && fn(node, parent, cache);
|
|
585
|
-
node.children.map((e) => dfsTree(e, fn, node.value ? node : null, cache));
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// dispose autorun, widget can be the virtual root widget
|
|
589
|
-
export function disposeWidget(widget, noRecursive = false) {
|
|
590
|
-
const disposers = widget._disposers;
|
|
591
|
-
disposers.map((dispose) => dispose());
|
|
592
|
-
disposers.splice(0, disposers.length);
|
|
593
|
-
!noRecursive && widget.children.forEach((w) => disposeWidget(w));
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
export function createInitData(widgets, dataBinds, keyPrefix = '') {
|
|
597
|
-
return Object.keys(widgets).reduce((result, id) => {
|
|
598
|
-
if (!isWidgetInFor(id, widgets, dataBinds)) {
|
|
599
|
-
result[keyPrefix + id] = resolveWidgetData(widgets[id], id);
|
|
600
|
-
} else {
|
|
601
|
-
result[keyPrefix + id] = [];
|
|
602
|
-
}
|
|
603
|
-
return result;
|
|
604
|
-
}, {});
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
function isWidgetInFor(id, widgets, dataBinds) {
|
|
608
|
-
let curNode = widgets[id];
|
|
609
|
-
let nodeId = id;
|
|
610
|
-
while (curNode) {
|
|
611
|
-
if (dataBinds[nodeId]?._waFor) {
|
|
612
|
-
return true;
|
|
613
|
-
}
|
|
614
|
-
nodeId = curNode._parentId;
|
|
615
|
-
curNode = widgets[nodeId];
|
|
616
|
-
}
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
function mountBuiltinWigetsAPI(widget, owner) {
|
|
620
|
-
// #1 builtin APIs
|
|
621
|
-
widget.findWidgets = function (filter, includeInvisibleDescendants) {
|
|
622
|
-
let { children = [] } = this;
|
|
623
|
-
if (!includeInvisibleDescendants) {
|
|
624
|
-
// include visible widgets only by default
|
|
625
|
-
children = children.filter((e) => e._waIf !== false);
|
|
626
|
-
}
|
|
627
|
-
const matched = [];
|
|
628
|
-
children.forEach((w) => {
|
|
629
|
-
if (filter(w)) {
|
|
630
|
-
matched.push(w);
|
|
631
|
-
}
|
|
632
|
-
matched.push(...w.findWidgets(filter, includeInvisibleDescendants));
|
|
633
|
-
});
|
|
634
|
-
return matched;
|
|
635
|
-
};
|
|
636
|
-
|
|
637
|
-
widget.getWidgetsByType = function (type, includeInvisibleDescendants) {
|
|
638
|
-
return this.findWidgets((w) => w.widgetType === type, includeInvisibleDescendants);
|
|
639
|
-
};
|
|
640
|
-
|
|
641
|
-
/**
|
|
642
|
-
* Similar to selectOwnerComponent of WX MP: https://developers.weixin.qq.com/miniprogram/dev/reference/api/Component.html
|
|
643
|
-
*/
|
|
644
|
-
widget.getOwnerWidget = function () {
|
|
645
|
-
return owner?._getInstance?.()?.node;
|
|
646
|
-
};
|
|
647
|
-
|
|
648
|
-
// Will be overwritten by composited component
|
|
649
|
-
widget.getDom = function (fields) {
|
|
650
|
-
return new Promise((resolve, reject) => {
|
|
651
|
-
const query = (owner || wx).createSelectorQuery();
|
|
652
|
-
query
|
|
653
|
-
.select(`#${this.id}`)
|
|
654
|
-
.fields(fields, (res) => {
|
|
655
|
-
resolve(res);
|
|
656
|
-
})
|
|
657
|
-
.exec();
|
|
658
|
-
});
|
|
659
|
-
};
|
|
660
|
-
|
|
661
|
-
widget.on = function (type, listener) {
|
|
662
|
-
this._eventListeners.on(type, listener);
|
|
663
|
-
};
|
|
664
|
-
|
|
665
|
-
widget.off = function (type, listener) {
|
|
666
|
-
this._eventListeners.off(type, listener);
|
|
667
|
-
};
|
|
668
|
-
|
|
669
|
-
widget.getConfig = () => ({});
|
|
670
|
-
|
|
671
|
-
const lowcode = compLowcodes[widget.widgetType];
|
|
672
|
-
if (lowcode) {
|
|
673
|
-
const { config } = lowcode;
|
|
674
|
-
widget.getConfig = () => config;
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
widget._getInstanceRef = () => widget._instanceRef;
|
|
678
|
-
|
|
679
|
-
/**
|
|
680
|
-
* @deprecated
|
|
681
|
-
*/
|
|
682
|
-
widget._methods = {};
|
|
683
|
-
|
|
684
|
-
Object.defineProperty(widget, '_userWidget', {
|
|
685
|
-
value: untracked(() => {
|
|
686
|
-
return new UserWidget(widget);
|
|
687
|
-
}),
|
|
688
|
-
});
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
/**
|
|
692
|
-
* 对外(用户)的 Widget
|
|
693
|
-
*/
|
|
694
|
-
class UserWidget {
|
|
695
|
-
_widget = null;
|
|
696
|
-
|
|
697
|
-
get description() {
|
|
698
|
-
const { id } = this._widget;
|
|
699
|
-
return `
|
|
700
|
-
使用说明:
|
|
701
|
-
1. sys 命名空间下为内置方法,可通过 $w.${id}.sys.<成员> 或 $w.${id}.<成员> 访问。
|
|
702
|
-
访问 id 示例: $w.${id}.id 或 $w.${id}.sys.id
|
|
703
|
-
2. custom 命名空间下为用户自定义对外暴露的成员,可通过 $w.${id}.custom.<成员> 或 $w.${id}.<成员> 访问。
|
|
704
|
-
访问自定义方法 hello 示例: $w.${id}.hello() 或 $w.${id}.custom.hello()
|
|
705
|
-
3. 通过 $w.${id}.<成员> 访问时,如果自定义成员与内置成员重名,则自定义成员覆盖内置成员。
|
|
706
|
-
4. [注意]: 请不要直接访问 _widget,它里面的成员为内部实现,随时可能进行调整
|
|
707
|
-
`;
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
constructor(widget) {
|
|
711
|
-
this._widget = widget;
|
|
712
|
-
return new Proxy(this, {
|
|
713
|
-
get(target, prop) {
|
|
714
|
-
if (prop in target) {
|
|
715
|
-
return target[prop];
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
/**
|
|
719
|
-
* @important
|
|
720
|
-
* 优先 custom
|
|
721
|
-
* 会出现一些 target 时序还不存在的情况
|
|
722
|
-
* 因此 custom[prop] 先添加进依赖
|
|
723
|
-
*/
|
|
724
|
-
if (target.custom?.[prop] !== undefined && prop in target.custom) {
|
|
725
|
-
return target.custom[prop];
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
// 再尝试内置的方法和属性
|
|
729
|
-
if (prop in target.sys) {
|
|
730
|
-
return target.sys[prop];
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
// 兼容原来的 widget。最后直接代理到 widget 上,主要是访问组件的属性
|
|
734
|
-
// return target._widget[prop];
|
|
735
|
-
return undefined;
|
|
736
|
-
},
|
|
737
|
-
/**
|
|
738
|
-
* userwidget 不可写
|
|
739
|
-
*/
|
|
740
|
-
set() {},
|
|
741
|
-
});
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
// 内置属性和方法命名空间
|
|
745
|
-
get sys() {
|
|
746
|
-
const widget = this._widget;
|
|
747
|
-
const [module, component] = widget.widgetType?.split?.(':') || [];
|
|
748
|
-
return {
|
|
749
|
-
/**
|
|
750
|
-
* 内置属性
|
|
751
|
-
*/
|
|
752
|
-
|
|
753
|
-
get id() {
|
|
754
|
-
return widget.id;
|
|
755
|
-
},
|
|
756
|
-
|
|
757
|
-
get module() {
|
|
758
|
-
return module;
|
|
759
|
-
},
|
|
760
|
-
|
|
761
|
-
get component() {
|
|
762
|
-
return component;
|
|
763
|
-
},
|
|
764
|
-
|
|
765
|
-
get name() {
|
|
766
|
-
return widget.widgetType;
|
|
767
|
-
},
|
|
768
|
-
|
|
769
|
-
get parent() {
|
|
770
|
-
return widget.parent?._userWidget;
|
|
771
|
-
},
|
|
772
|
-
|
|
773
|
-
get children() {
|
|
774
|
-
return widget.children?.map((item) => item._userWidget) || [];
|
|
775
|
-
},
|
|
776
|
-
|
|
777
|
-
/**
|
|
778
|
-
* 内置方法
|
|
779
|
-
*/
|
|
780
|
-
|
|
781
|
-
closest(filter) {
|
|
782
|
-
let { parent } = this;
|
|
783
|
-
if (!filter) return parent;
|
|
784
|
-
|
|
785
|
-
while (parent) {
|
|
786
|
-
const matched = filter(parent);
|
|
787
|
-
if (matched) return parent;
|
|
788
|
-
|
|
789
|
-
parent = parent.parent;
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
return null;
|
|
793
|
-
},
|
|
794
|
-
};
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
get custom() {
|
|
798
|
-
const widget = this._widget;
|
|
799
|
-
const userCustomMember = untracked(() => {
|
|
800
|
-
const instanceRef = widget._getInstanceRef?.();
|
|
801
|
-
const instance = instanceRef?.current || {};
|
|
802
|
-
const { methods = {}, ...restInstance } = instance;
|
|
803
|
-
return new Proxy(
|
|
804
|
-
{
|
|
805
|
-
...widget?._methods,
|
|
806
|
-
...restInstance,
|
|
807
|
-
...methods,
|
|
808
|
-
},
|
|
809
|
-
{
|
|
810
|
-
get(_, prop) {
|
|
811
|
-
if (prop in methods) {
|
|
812
|
-
return methods[prop];
|
|
813
|
-
}
|
|
814
|
-
/**
|
|
815
|
-
* 此处要保持从 ref 开始访问
|
|
816
|
-
* 因为proxy 内部如果直接从 ref.current 开始访问,刚开始是可能遇到的是空值,并且空对象兜底
|
|
817
|
-
* 那么此处实际上监听的即为兜底的空对象,非 observer 对象
|
|
818
|
-
*/
|
|
819
|
-
if (prop !== 'methods' && prop in (instanceRef.current || {})) {
|
|
820
|
-
return instance[prop];
|
|
821
|
-
}
|
|
822
|
-
return widget?._methods?.[prop];
|
|
823
|
-
},
|
|
824
|
-
},
|
|
825
|
-
);
|
|
826
|
-
});
|
|
827
|
-
return userCustomMember;
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
export function generateWidgetAPIContext($w = {}, widget, forContext) {
|
|
832
|
-
return new Proxy($w, {
|
|
833
|
-
get(target, prop) {
|
|
834
|
-
// debugger;
|
|
835
|
-
|
|
836
|
-
/**
|
|
837
|
-
* for context 变量优先
|
|
838
|
-
*/
|
|
839
|
-
const { lists = [] } = forContext;
|
|
840
|
-
for (const meta of lists) {
|
|
841
|
-
const map = meta.alias || {};
|
|
842
|
-
if (prop in map) {
|
|
843
|
-
return map[prop];
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
// 尝试代理同级 widget
|
|
848
|
-
if (widget) {
|
|
849
|
-
let { parent } = widget;
|
|
850
|
-
while (parent) {
|
|
851
|
-
if (parent._descendants?.[prop]) {
|
|
852
|
-
return parent._descendants[prop]._userWidget;
|
|
853
|
-
}
|
|
854
|
-
parent = parent.parent;
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
// 尝试代理到全局的 $w
|
|
859
|
-
return target[prop];
|
|
860
|
-
},
|
|
861
|
-
});
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
function isRepeaterWidget(
|
|
865
|
-
w /* : { widgetType: string; getConfig: () => { componentType?: string } } */,
|
|
866
|
-
repeaterComponentName /* : string */ /* 'Repeater' | 'RepeaterItem' */,
|
|
867
|
-
) {
|
|
868
|
-
const { componentType } = w?.getConfig?.() || {};
|
|
869
|
-
if (componentType === repeaterComponentName || w?.widgetType === `${REPEATER.MODULE_NAME}:${repeaterComponentName}`) {
|
|
870
|
-
return true;
|
|
871
|
-
}
|
|
872
|
-
}
|