@cloudbase/lowcode-builder 1.7.1 → 1.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { observable } from 'mobx';
2
- import { createComputed, createEventHandlers, checkAuth } from './util';
2
+ import { createComputed, createEventHandlers, checkAuth, getMpEventHandlerName, generateDatasetQuery, generateEventFlows } from './util';
3
3
  import { createWidgets, createInitData, disposeWidget, ID_SEPARATOR, getWidget } from './widget';
4
4
  import mergeRenderer from './merge-renderer';
5
5
  import {
@@ -10,27 +10,27 @@ import {
10
10
  setConfig,
11
11
  } from '../datasources/index';
12
12
  import { runWatchers } from './watch';
13
- import { getMpEventHandlerName } from './util';
14
- import { $w as baseAPI } from '../app/app-global';
13
+ import { $w as baseAPI } from '../app/weapps-api'
14
+ import { Event } from './event-emitter'
15
15
 
16
16
  const wxApp = getApp()
17
17
 
18
- export function createPage(
18
+ export function createPage({
19
+ app,
19
20
  id,
20
- uuid,
21
- title,
22
21
  widgetProps,
23
22
  index = {},
24
23
  lifecycle,
25
- pageState,
26
- pageComputed,
24
+ state,
25
+ computed,
27
26
  evtListeners,
28
27
  dataBinds,
29
- app,
30
- handler,
28
+ handlers,
29
+ query: datasetQuery = {},
30
+ eventFlows = [],
31
31
  pageContext = {},
32
- pageAttributes,
33
- ) {
32
+ pageAttributes = {},
33
+ }) {
34
34
  const evtHandlers = createEventHandlers(evtListeners);
35
35
 
36
36
  function extractLifecycles() {
@@ -69,7 +69,7 @@ export function createPage(
69
69
  // 更新设备信息 窗口信息
70
70
  result['onResize'] = (res) => {
71
71
  let device = baseAPI.device;
72
- if(!device) {
72
+ if (!device) {
73
73
  return
74
74
  }
75
75
  const width = res?.size?.windowWidth;
@@ -89,6 +89,7 @@ export function createPage(
89
89
  data: createInitData(widgetProps, dataBinds),
90
90
  lifetimes: {
91
91
  attached() {
92
+ this._disposers = []
92
93
  const $page = this._getInstance();
93
94
  this._pageActive = true;
94
95
  /**
@@ -107,7 +108,7 @@ export function createPage(
107
108
  const widget = getWidget($page.widgets, e.target.id);
108
109
  widget._methods = {};
109
110
  };
110
- this._disposers = this.initMergeRenderer($page.widgets);
111
+ this._disposers.push( ...this.initMergeRenderer($page.widgets));
111
112
  },
112
113
  detached() {
113
114
  const $page = this._getInstance();
@@ -120,8 +121,8 @@ export function createPage(
120
121
  },
121
122
  pageLifetimes: {
122
123
  // 组件所在页面的生命周期函数,定义下给运营平台上报用
123
- show: function () {},
124
- hide: function () {},
124
+ show: function () { },
125
+ hide: function () { },
125
126
  },
126
127
  methods: {
127
128
  _pageActive: true,
@@ -133,20 +134,31 @@ export function createPage(
133
134
  ...evtHandlers,
134
135
  ...mergeRenderer,
135
136
  async beforePageCustomLaunch(query) {
136
- if(!this._beforePageCustomLaunchPromise){
137
- this._beforePageCustomLaunchPromise = new Promise(async (resolve)=>{
137
+ if (!this._beforePageCustomLaunchPromise) {
138
+ this._beforePageCustomLaunchPromise = new Promise(async (resolve) => {
138
139
  await wxApp.globaldata?._beforePageCustomLaunchPromise
139
140
  const $page = this._getInstance();
140
- if(query){
141
+ if (query) {
141
142
  EXTRA_API.setParams($page.uuid, query);
142
143
  }
143
- if(await checkAuth(app, app.id, $page)){
144
+ if (await checkAuth(app, app.id, $page)) {
144
145
  this.setData({
145
146
  weDaHasLogin: true,
146
147
  });
147
148
  createStateDataSourceVar($page.uuid, generateParamsParser({ app, $page }));
148
- resolve()
149
149
  }
150
+ // eslint-disable-next-line no-restricted-syntax
151
+ for (const queryId in $page.dataset?.query||{}) {
152
+ if ($page.dataset.query[queryId]?._schema?.trigger === 'auto') {
153
+ try {
154
+ $page.dataset.query[queryId].trigger();
155
+ this._disposers.push($page.dataset.query[queryId].destroy)
156
+ } catch (e) {
157
+ console.error(`query ${queryId} 初始化失败:`, e);
158
+ }
159
+ }
160
+ }
161
+ resolve()
150
162
  })
151
163
  }
152
164
  return this._beforePageCustomLaunchPromise
@@ -164,7 +176,7 @@ export function createPage(
164
176
 
165
177
  const hook = lifecycle.onLoad || lifecycle.onPageLoad;
166
178
  await hook?.call?.($page, this._query);
167
- this.invokeEventHandler(id, 'load', { detail: { query: this._query } });
179
+ this._invokeEventHandler('load', { query: this._query });
168
180
  },
169
181
  async onReady() {
170
182
  const $page = this._getInstance();
@@ -174,7 +186,7 @@ export function createPage(
174
186
  const hook = lifecycle.onReady || lifecycle.onPageReady;
175
187
  await hook?.call?.($page);
176
188
 
177
- this.invokeEventHandler(id, 'ready');
189
+ this._invokeEventHandler(id, 'ready');
178
190
  },
179
191
  onUnload() {
180
192
  const $page = this._getInstance();
@@ -182,7 +194,7 @@ export function createPage(
182
194
  const hook = lifecycle.onUnload || lifecycle.onPageUnload;
183
195
  hook?.call?.($page);
184
196
 
185
- this.invokeEventHandler(id, 'unload');
197
+ this._invokeEventHandler('unload');
186
198
  },
187
199
  async onShow() {
188
200
  const $page = this._getInstance();
@@ -195,21 +207,25 @@ export function createPage(
195
207
 
196
208
  const hook = lifecycle.onShow || lifecycle.onPageShow;
197
209
  await hook?.call?.($page);
198
- this.invokeEventHandler(id, 'show');
210
+ this._invokeEventHandler('show');
199
211
  },
200
212
  onHide() {
201
213
  const $page = this._getInstance();
202
214
  const hook = lifecycle.onHide || lifecycle.onPageHide;
203
215
  hook?.call?.($page);
204
216
  this._pageActive = false;
205
- $page.__internal__.active = this._pageActive;
206
217
 
207
218
  // 触发页面节点事件
208
- this.invokeEventHandler(id, 'hide');
219
+ this._invokeEventHandler('hide');
220
+ $page.__internal__.active = this._pageActive;
209
221
  },
210
- invokeEventHandler(id, triggerName, params = {}) {
222
+ _invokeEventHandler(triggerName, params = {}) {
211
223
  const keyName = getMpEventHandlerName(id, triggerName);
212
- typeof evtHandlers?.[keyName] === 'function' && evtHandlers[keyName].call(this, params);
224
+ const event = new Event({
225
+ type: triggerName,
226
+ detail: params
227
+ })
228
+ return this[keyName]?.call?.(this, event)
213
229
  },
214
230
  _getInstance() {
215
231
  let $page = this.$WEAPPS_PAGE;
@@ -218,20 +234,23 @@ export function createPage(
218
234
  }
219
235
  Object.assign(pageContext, {
220
236
  id,
221
- uuid,
222
- state: observable(pageState),
237
+ state: observable(state),
223
238
  path: this.route,
224
- label: title,
225
239
  widgets: {},
226
240
  });
227
241
  $page = pageContext;
228
242
  this.$WEAPPS_PAGE = $page;
229
- $page.handler = Object.keys(handler).reduce((result, key) => {
230
- result[key] = handler[key].bind($page);
243
+ $page.handler = Object.keys(handlers).reduce((result, key) => {
244
+ result[key] = handlers[key].bind($page);
231
245
  return result;
232
246
  }, {});
233
- $page.computed = createComputed(pageComputed, $page);
247
+ $page.computed = createComputed(computed, $page);
234
248
  let dataset = createDataset($page.uuid);
249
+ dataset.query = generateDatasetQuery(datasetQuery, {
250
+ $w: $page.__internal__.$w,
251
+ $app: app,
252
+ $page,
253
+ })
235
254
  $page.dataset = dataset;
236
255
  $page.state.dataset = dataset;
237
256
  $page.setState = (userSetState) => {
@@ -240,7 +259,7 @@ export function createPage(
240
259
  });
241
260
  };
242
261
 
243
- const { widgets, rootWidget } = createWidgets(widgetProps, dataBinds, this, $page.widgets);
262
+ const { widgets, rootWidget } = createWidgets(widgetProps, dataBinds, this, $page.widgets);
244
263
  $page.widgets = widgets
245
264
  $page._rootWidget = rootWidget;
246
265
 
@@ -270,6 +289,11 @@ export function createPage(
270
289
  }
271
290
  return readonlyMap[method](params);
272
291
  };
292
+ $page.__internal__.eventFlows = generateEventFlows(eventFlows, {
293
+ $w: $page.__internal__.$w,
294
+ $app: app,
295
+ $page,
296
+ });
273
297
 
274
298
  return $page;
275
299
  },
@@ -3,7 +3,10 @@ import { $w as baseAPI } from '<%= subLevelPath %>../../app/weapps-api'
3
3
  export const $page = {
4
4
  __internal__: {
5
5
  active: false
6
- }
6
+ },
7
+ uuid: '<%= uuid %>',
8
+ label: '<%= label %>',
9
+
7
10
  };
8
11
 
9
12
  export const $w = new Proxy(
@@ -16,6 +19,17 @@ export const $w = new Proxy(
16
19
  if (prop === '$page' || prop === 'page') {
17
20
  return $page;
18
21
  }
22
+
23
+ // 代理页面级 query
24
+ if ($page.dataset?.query?.[prop]) {
25
+ return $page.dataset.query[prop];
26
+ }
27
+
28
+ // 代理页面 flow
29
+ if ($page.__internal__.eventFlows?.[prop]) {
30
+ return $page.__internal__.eventFlows[prop];
31
+ }
32
+
19
33
  // 尝试代理页面级别组件实例
20
34
  const pageWidget = $page.widgets?.[prop];
21
35
  if (pageWidget) {
@@ -3,34 +3,87 @@ import { createPage } from '<%= subLevelPath %>../../common/weapp-page'
3
3
  import { concatClassList, px2rpx } from '<%= subLevelPath %>../../common/style'
4
4
  import { app, $app } from '<%= subLevelPath %>../../app/weapps-api'
5
5
  import { $$<%= pageName %> as handlers } from '../../app/handlers'
6
- <%= importor.lifecycle? `import lifecyle from '../../lowcode/${pageName}/lifecycle'` : "const lifecyle = {}" %>
6
+ <%= importor.lifecycle? `import lifecycle from '../../lowcode/${pageName}/lifecycle'` : "const lifecycle = {}" %>
7
7
  <%= importor.state? `import state from '../../lowcode/${pageName}/state'` : "const state = {}" %>
8
8
  <%= importor.computed? `import computed from '../../lowcode/${pageName}/computed'` : "const computed = {}" %>
9
- import { $page } from './api'
9
+ import { $page, $w } from './api'
10
10
  import { widgetProps } from './data'
11
11
 
12
+ <% function printBoundData(boundData={}) {
13
+ const list = []
14
+ Object.entries(boundData).map(([prop, bindMeta])=>{
15
+ const str = `'${prop}': ($page, lists, forItems, event, $context, $w) => {${bindMeta.imports} return(
16
+ ${bindMeta.expression === '' ? 'undefined': bindMeta.expression}
17
+ )}`
18
+ list.push(str)
19
+ })
20
+ return list.join(',')
21
+ }%>
22
+
23
+ <% function printEventHandler(eventHandlers) {
24
+ Object.entries(eventHandlers).map(([handlerName, listeners])=>{
25
+ print(`"${handlerName}": [
26
+ ${listeners.map(l=>{
27
+ let handler = 'undefined'
28
+ switch(l.type){
29
+ case 'rematch': {
30
+ handler = `handlers.${l.handler}`
31
+ break;
32
+ }
33
+ case 'material': {
34
+ handler = `function(...args) { return require('../../materials/${l.handlerModule}/actions/${l.handler}/index').default(...args) }`
35
+ break;
36
+ }
37
+ default: {
38
+ handler = l.handler
39
+ }
40
+ }
41
+ return `{
42
+ key: '${l.key||''}',
43
+ sourceKey: '${ l.sourceKey||"" }',
44
+ handler: ${handler},
45
+ data: ${stringifyObj(l.data||{}, {depth: null})},
46
+ boundData: {${printBoundData(l.boundData)}}
47
+ }`
48
+ }).join(',')}
49
+ ],`)
50
+ })
51
+ }%>
52
+
12
53
  /** widget event listeners **/
13
- const evtListeners = {<% Object.entries(eventHanlders).map(([handlerName, listeners])=>{%>
14
- <%= handlerName%>: [
15
- <%listeners.map(l=> { %>{
16
- key: '<%= l.key %>',
17
- sourceKey: '<%= l.sourceKey %>',
18
- handler: <% if (l.type === 'rematch') {%> handlers.<%= l.handler %> <%} else if (l.type == 'material') {%> function(...args) { return require('../../materials/<%= l.handlerModule %>/actions/<%= l.handler %>/index').default(...args) } <%} else {%> <%= l.handler %> <%} %>,
19
- data: <%= stringifyObj(l.data, {depth: null}) %>,
20
- boundData: {<% Object.entries(l.boundData).map(([prop, bindMeta])=>{%>'<%= prop %>':($page, lists, forItems, event, $context, $w) => {<%= bindMeta.imports %> return (
21
- <%= bindMeta.expression === '' ? 'undefined': bindMeta.expression %>
22
- )},
23
- <%}) %>}
24
- },<%})%>
25
- ],<%})%>
26
- }
54
+ const evtListeners = {<% printEventHandler(eventHandlers) %>}
27
55
 
28
56
  const dataBinds = {<% Object.entries(dataBinds).map(([id, widgetBinds])=>{%>
29
- <%= id %>: { <% Object.entries(widgetBinds).map(([prop, bindMeta]) => { %>
30
- "<%= prop %>": function ($page, lists, forItems, event, $context, $w) {<%= bindMeta.imports %> return (
31
- <%= bindMeta.expression === '' ? 'undefined': bindMeta.expression %>
32
- ); },<% }) %>
57
+ <%= id %>: { <%= printBoundData(widgetBinds) %>
33
58
  },<%}) %>
34
59
  }
35
60
 
36
- createPage('<%= pageName %>', '<%= pageUUID %>','<%= pageTitle %>', widgetProps, {}, lifecyle, state, computed, evtListeners, dataBinds, app, handlers, $page, <%= pageAttributes?JSON.stringify(pageAttributes):'{}' %>)
61
+ const query = {<% Object.entries(query).map(([id, item])=>{%>
62
+ <%= id %>: { <% const {dataBinds={}, eventHandlers, ...rest } = item %>
63
+ ...(<%= stringifyObj(rest, {depth: null}) %>),
64
+ dataBinds: {<%= printBoundData(dataBinds) %>},
65
+ eventHandlers: {<% printEventHandler(eventHandlers) %>}
66
+ },<%}) %>
67
+ }
68
+
69
+ const eventFlows = [<% eventFlows.map(flow => {%> { <% const { eventHandlers, ...rest } = flow %>
70
+ ...(<%= stringifyObj(rest, {depth: null}) %>),
71
+ eventHandlers: {<% printEventHandler(eventHandlers) %>}
72
+ },<%}) %>
73
+ ]
74
+
75
+ createPage({
76
+ app,
77
+ pageContext: $page,
78
+ id: '<%= pageName %>',
79
+ widgetProps,
80
+ lifecycle,
81
+ state,
82
+ computed,
83
+ evtListeners,
84
+ dataBinds,
85
+ handlers,
86
+ query,
87
+ eventFlows,
88
+ pageAttributes: <%= pageAttributes? stringifyObj(pageAttributes, {depth: null}):'{}' %>
89
+ })
@@ -1,49 +0,0 @@
1
- function checkFunc (listener) {
2
- if (!listener instanceof Function) {
3
- throw new Error(
4
- " The listener argument must be of type Function. "
5
- );
6
- }
7
- }
8
-
9
- export default class EventEmitter {
10
- constructor () {
11
- this.listeners = {};
12
- }
13
-
14
- on (eventName, listener) {
15
- checkFunc(listener)
16
- let listeners = this.listeners[eventName]
17
- if (!listeners) {
18
- this.listeners[eventName] = [listener]
19
- }
20
- else {
21
- listeners.push(listener)
22
- }
23
- }
24
-
25
- off (eventName, listener) {
26
- let listeners = this.listeners[eventName]
27
- if (listeners && listeners.length) {
28
- const index = listeners.indexOf(listener)
29
- index > -1 && listeners.splice(index, 1)
30
- }
31
- }
32
-
33
-
34
- emit (eventName, ...args) {
35
- let listeners = this.listeners[eventName] || []
36
- listeners.forEach(fn => {
37
- try {
38
- fn.call(this, ...args)
39
- } catch (err) {
40
- console.error(err);
41
- }
42
- }
43
- );
44
- }
45
-
46
- clear () {
47
- this.listeners = {};
48
- }
49
- }
@@ -1,106 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
4
- var b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
5
- exports.weBtoa = function (string) {
6
- string = String(string);
7
- var bitmap,
8
- a,
9
- b,
10
- c,
11
- result = "",
12
- i = 0,
13
- rest = string.length % 3;
14
- for (; i < string.length; ) {
15
- if (
16
- (a = string.charCodeAt(i++)) > 255 ||
17
- (b = string.charCodeAt(i++)) > 255 ||
18
- (c = string.charCodeAt(i++)) > 255
19
- )
20
- throw new TypeError(
21
- "Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range."
22
- );
23
- bitmap = (a << 16) | (b << 8) | c;
24
- result +=
25
- b64.charAt((bitmap >> 18) & 63) +
26
- b64.charAt((bitmap >> 12) & 63) +
27
- b64.charAt((bitmap >> 6) & 63) +
28
- b64.charAt(bitmap & 63);
29
- }
30
- return rest ? result.slice(0, rest - 3) + "===".substring(rest) : result;
31
- };
32
- exports.weAtob = function (string) {
33
- string = String(string).replace(/[\t\n\f\r ]+/g, "");
34
- if (!b64re.test(string))
35
- throw new TypeError(
36
- "Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded."
37
- );
38
- string += "==".slice(2 - (string.length & 3));
39
- var bitmap,
40
- result = "",
41
- r1,
42
- r2,
43
- i = 0;
44
- for (; i < string.length; ) {
45
- bitmap =
46
- (b64.indexOf(string.charAt(i++)) << 18) |
47
- (b64.indexOf(string.charAt(i++)) << 12) |
48
- ((r1 = b64.indexOf(string.charAt(i++))) << 6) |
49
- (r2 = b64.indexOf(string.charAt(i++)));
50
- result +=
51
- r1 === 64
52
- ? String.fromCharCode((bitmap >> 16) & 255)
53
- : r2 === 64
54
- ? String.fromCharCode((bitmap >> 16) & 255, (bitmap >> 8) & 255)
55
- : String.fromCharCode(
56
- (bitmap >> 16) & 255,
57
- (bitmap >> 8) & 255,
58
- bitmap & 255
59
- );
60
- }
61
- return result;
62
- };
63
- function b64DecodeUnicode(str) {
64
- return decodeURIComponent(
65
- exports.weAtob(str).replace(/(.)/g, function (p) {
66
- var code = p.charCodeAt(0).toString(16).toUpperCase();
67
- if (code.length < 2) {
68
- code = "0" + code;
69
- }
70
- return "%" + code;
71
- })
72
- );
73
- }
74
- function base64_url_decode(str) {
75
- var output = str.replace(/-/g, "+").replace(/_/g, "/");
76
- switch (output.length % 4) {
77
- case 0:
78
- break;
79
- case 2:
80
- output += "==";
81
- break;
82
- case 3:
83
- output += "=";
84
- break;
85
- default:
86
- throw "Illegal base64url string!";
87
- }
88
- try {
89
- return b64DecodeUnicode(output);
90
- } catch (err) {
91
- return exports.weAtob(output);
92
- }
93
- }
94
- function weappJwtDecode(token, options) {
95
- if (typeof token !== "string") {
96
- throw "Invalid token specified";
97
- }
98
- options = options || {};
99
- var pos = options.header === true ? 0 : 1;
100
- try {
101
- return JSON.parse(base64_url_decode(token.split(".")[pos]));
102
- } catch (e) {
103
- throw "Invalid token specified: " + e.message;
104
- }
105
- }
106
- exports.default = weappJwtDecode;
@@ -1,76 +0,0 @@
1
- import { urlJoinParams } from './url'
2
- import { promisifyAll } from 'miniprogram-api-promise'
3
-
4
- function createNavigatorFn(fnName) {
5
- return function ({ pageId, packageName, params, mode='', events, success, fail, complete }) {
6
- let url;
7
- if(mode == 'plugin'){
8
- url = `plugin://${packageName}/${pageId}`
9
- } else if(mode ==='web'){
10
- console.warn(`${fnName} url can only be used in h5 build`);
11
- return;
12
- } else {
13
- pageId = pageId ? pageId.replace(/^(\.)?\//,'') : pageId;
14
- url = packageName
15
- ? `/${packageName}/pages/${pageId}/index`
16
- : `/pages/${pageId}/index`
17
- }
18
-
19
- if (fnName === 'navigateTo') {
20
- navigateToFn(urlJoinParams(url, params), { events, success, fail, complete});
21
- return;
22
- }
23
-
24
- wx[fnName]({
25
- url: urlJoinParams(url, params),
26
- events,
27
- success,
28
- fail,
29
- complete
30
- })
31
- }
32
- }
33
-
34
- /**
35
- * 页面堆栈10以内使用wx.navigateTo,超过10则使用wx.redirectTo
36
- * @param url
37
- * @param param1
38
- * @returns
39
- */
40
- function navigateToFn(url, { events, success, fail, complete}) {
41
- const pages = getCurrentPages();
42
- if(pages && pages.length >= 10) {
43
- wx.redirectTo({
44
- url,
45
- success,
46
- fail,
47
- complete
48
- });
49
- return;
50
- }
51
-
52
- wx.navigateTo({
53
- url,
54
- // @types/weixin-app@2.9.3没有events的定义,但实际上官方文档有:https://developers.weixin.qq.com/miniprogram/dev/api/route/wx.navigateTo.html
55
- // @ts-ignore
56
- events,
57
- success,
58
- fail,
59
- complete
60
- });
61
- }
62
-
63
- const navigateTo = createNavigatorFn('navigateTo')
64
- const reLaunch = createNavigatorFn('reLaunch')
65
- const redirectTo = createNavigatorFn('redirectTo')
66
-
67
- export const wxp = {}
68
- promisifyAll(wx, wxp)
69
-
70
- export default {
71
- ...wxp,
72
- navigateTo,
73
- reLaunch,
74
- redirectTo,
75
- auth: undefined
76
- }