@cc-component/cc-ex-component 1.1.8 → 1.1.9

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,20 +1,37 @@
1
1
  import { _decorator, Component, Node } from 'cc';
2
2
  import { ReferenceComponent } from './ReferenceComponent';
3
+ import { BaseViewModelData } from './BaseViewModelData';
3
4
  const { ccclass, property } = _decorator;
4
5
 
5
6
  @ccclass('BaseReference')
6
7
  export class BaseReference extends Component {
7
8
  rc: ReferenceComponent;
8
9
  isInit: boolean = false;
10
+ isLoad: boolean = false;
11
+ vmParams: any;
12
+ viewModel: BaseViewModelData;
9
13
  initReferenceCollector() {
14
+ if (this.isInit) return;
15
+ this.isInit = true;
10
16
  this.rc = this.getComponent(ReferenceComponent);
11
17
  }
18
+
19
+ onLoadFinish() {
20
+ if (this.isLoad) return;
21
+ this.isLoad = true;
22
+ if (this.vmParams) this.viewModel?.refreshUI(this.vmParams)
23
+ }
12
24
  //#endregion
13
25
  defineProperty(propertyKey: string) {
14
26
  Object.defineProperty(this, propertyKey, { get: () => this.rc.get(propertyKey) });
15
27
  }
16
28
 
17
29
 
30
+ refreshUI(vmParams: any) {
31
+ this.vmParams = vmParams;
32
+ }
33
+
34
+
18
35
  // // 在 test 类中添加
19
36
  // protected _bindings: { uiProp: string; dataPath: string }[] = [];
20
37
 
@@ -34,7 +34,7 @@ export class ReferenceComponent extends Component {
34
34
 
35
35
  @property
36
36
  private _refresh_bind = false;
37
- @property({ displayName: "快速生成vm属性" })
37
+ @property({ displayName: "生成UI属性" })
38
38
  private get refresh_bind() { return this._refresh_bind; }
39
39
  private set refresh_bind(val: boolean) {
40
40
  if (EDITOR_NOT_IN_PREVIEW) {
@@ -46,7 +46,7 @@ export class ReferenceComponent extends Component {
46
46
 
47
47
  @property
48
48
  private _refresh_bind_data = false;
49
- @property({ displayName: "快速生成vm Data" })
49
+ @property({ displayName: "生成UI数据对象" })
50
50
  private get refresh_bind_data() { return this._refresh_bind_data; }
51
51
  private set refresh_bind_data(val: boolean) {
52
52
  if (EDITOR_NOT_IN_PREVIEW) {
@@ -55,6 +55,18 @@ export class ReferenceComponent extends Component {
55
55
  }
56
56
  this._refresh_bind_data = false;
57
57
  }
58
+ @property
59
+ private _refresh_bind_data_all = false;
60
+ @property({ displayName: "生成模板" })
61
+ private get refresh_bind_data_all() { return this._refresh_bind_data_all; }
62
+ private set refresh_bind_data_all(val: boolean) {
63
+ if (EDITOR_NOT_IN_PREVIEW) {
64
+ this.initNodeList();
65
+ this.genCodeVmDataAll();
66
+ }
67
+ this._refresh_bind_data_all = false;
68
+ }
69
+
58
70
 
59
71
  @property({ type: CollectorNodeData, readonly: false })
60
72
  private _nodes: CollectorNodeData[] = [];
@@ -66,6 +78,8 @@ export class ReferenceComponent extends Component {
66
78
  private _nodeMap: Map<string, Node | Sprite> = new Map();
67
79
 
68
80
  comList = ["EditBox", "Toggle", "ToggleContainer", "Slider", "Button", "ProgressBar", "YXCollectionView", "TableView"]
81
+ comList2 = ["YXCollectionView", "TableView"]
82
+ comList_base = ["EditBox", "Toggle", "ToggleContainer", "Slider", "Button", "ProgressBar"]
69
83
 
70
84
  protected onLoad(): void {
71
85
  if (EDITOR_NOT_IN_PREVIEW) {//处理编辑器逻辑
@@ -175,16 +189,23 @@ export class ReferenceComponent extends Component {
175
189
  }
176
190
 
177
191
  /** 生成引用节点的获取代码 并复制到剪切板 */
178
- private genCodeBind(isVm: boolean = true) {
192
+ private genCodeBind(isCopy: boolean = true, isClass: boolean = false) {
179
193
  if (!EDITOR_NOT_IN_PREVIEW) return;
180
194
  let text = "";
181
-
182
-
195
+ let eventStr: string = " //#region ✅ 事件"
196
+ let pix = "onClick_"
197
+ // const com = this.node.components.find(v => { return v.reference })
198
+ // const match = com.name.match(/<([^>]+)>/);
199
+ // const className = match && match[1] ? match[1] : "any"
200
+ const className = this.node.name
201
+
202
+ console.error("[MLogger Error]", className)
183
203
  const viewModel = `
184
- // ✅ 使用新装饰器(自动响应式 + 路径推导)
185
- @BindViewModel(new ViewModelData())
186
- viewModel: ViewModelData;`
187
- text += viewModel + "\n"
204
+ //#region ✅ 使用新装饰器(自动响应式 + 路径推导)
205
+ @BindViewModel(new ${className}Data())
206
+ viewModel: ${className}Data;`
207
+ text += viewModel + "\n\n"
208
+ text += ` //#region ✅ UI属性`
188
209
  //生成get属性
189
210
  this.nodes.forEach(data => {
190
211
  let key = data.key;
@@ -192,19 +213,19 @@ export class ReferenceComponent extends Component {
192
213
  let name = key[0].toLowerCase() + key.substring(1);
193
214
  const type = this.getPropertyType(data.com)
194
215
  let bind_pix = `@Bind`
195
- let event = `,{ event: (self) => { } }`
216
+ let event = `,{ event: (self:${className}) => { } }`
196
217
  if (type === "YXCollectionView") {
197
218
  event = `, {
198
- layout: (self) => {
219
+ layout: (self:${className}) => {
199
220
  const layout = new YXFlowLayout();
200
221
  layout.horizontalSpacing = 10;
201
222
  layout.verticalSpacing = 20;
202
223
  layout.itemSize = () => math.size(100, 100);
203
224
  return layout;
204
225
  },
205
- cellForItemAt: (self, indexPath, collectionView) => {
206
- let node = collectionView.dequeueReusableCell("cell", indexPath);
207
- // TODO: configure cell
226
+ cellForItemAt: (self:${className}, indexPath, collectionView) => {
227
+ const node = collectionView.dequeueReusableCell("cell", indexPath);
228
+ //node.getComponent(TableVIewItem).refreshUI(self.viewModel.${name}[indexPath.row])
208
229
  return node;
209
230
  },
210
231
  }`
@@ -213,8 +234,9 @@ export class ReferenceComponent extends Component {
213
234
  } else if (type === "TableView") {
214
235
  event = `, {
215
236
  itemSize: () => math.size(100, 100),
216
- cellForItemAt: (self, indexPath, collectionView) => {
217
- let node = collectionView.dequeueReusableCell("cell", indexPath)
237
+ cellForItemAt: (self:${className}, indexPath, collectionView) => {
238
+ const node = collectionView.dequeueReusableCell("cell", indexPath)
239
+ //node.getComponent(TableVIewItem).refreshUI(self.viewModel.${name}[indexPath.row])
218
240
  return node
219
241
  },
220
242
  }`
@@ -222,20 +244,42 @@ export class ReferenceComponent extends Component {
222
244
  }
223
245
 
224
246
  let bind = `${bind_pix}("${name}"${this.comList.includes(type) ? event : ""})`
247
+ if (isClass) {
248
+ bind = `${bind_pix}("${name}"${this.comList2.includes(type) ? event : ""})`
249
+ }
250
+ if (this.comList_base.includes(type)) {
251
+
252
+ eventStr += `
253
+ ${pix}${name}(comp: ${type === "ToggleContainer" ? "Toggle" : type}) {
254
+
255
+ }\n`
256
+
257
+ }
225
258
  //@ts-ignore
226
259
  let line = ` ${bind} @Ref ${name}: ${type};`
227
260
  text += line;
228
261
  });
229
262
 
230
263
 
231
- Editor.Clipboard.write("text", text);
232
- console.log("已复制到剪切板");
264
+ if (isCopy) {
265
+ Editor.Clipboard.write("text", text);
266
+ console.log("已复制到剪切板");
267
+ }
268
+ return { text: text, event: eventStr }
269
+
233
270
  }
234
271
 
235
272
  /** 生成引用节点的获取代码 并复制到剪切板 */
236
- private genCodeVmData() {
273
+ private genCodeVmData(isCopy: boolean = true) {
237
274
  if (!EDITOR_NOT_IN_PREVIEW) return;
238
275
  let text = ""
276
+ let sx_this = ''
277
+ let sx = ' \n'
278
+ const className = this.node.name
279
+
280
+ let data = `${className}Data`
281
+ let iinterface = `I${className}Data`
282
+
239
283
  //生成get属性
240
284
  this.nodes.forEach(data => {
241
285
  let key = data.key;
@@ -243,18 +287,78 @@ export class ReferenceComponent extends Component {
243
287
  const type = this.getPropertyType(data.com)
244
288
  //@ts-ignore
245
289
  let line = ` ${name}: ${this.getDataTypeByComponentType(type)};`//`private get ${name}() { return this.rc.get("${key}", ${this.getPropertyType(data.node)}); }`;
246
- text += line + "\n";
290
+ sx += line + "\n";
291
+
292
+ let line_sx = ` this.${name} = ${this.getDataTypeByComponentTypeValue(type)}`
293
+ sx_this += line_sx + '\n'
247
294
  });
248
295
 
249
296
  text = `
250
- class ViewModelData {
251
- ${text}
297
+ //#region 数据接口
298
+ export interface ${iinterface} {
299
+ ${sx}
300
+ }
301
+ `;
302
+ text += `
303
+ //#region ✅ 数据VM
304
+ class ${data} extends BaseViewModelData implements ${iinterface} {
305
+ ${sx}
252
306
 
307
+ // ✅ 本界面内部调用
253
308
  loadData() {
254
-
309
+ ${sx_this}
255
310
  }
256
311
  }
257
312
  `;
313
+ if (isCopy) {
314
+ Editor.Clipboard.write("text", text);
315
+ console.log("已复制到剪切板");
316
+ }
317
+ return text
318
+ }
319
+
320
+
321
+
322
+
323
+ /** 生成引用节点的获取代码 并复制到剪切板 */
324
+ private genCodeVmDataAll() {
325
+ if (!EDITOR_NOT_IN_PREVIEW) return;
326
+ let text = `
327
+ import { _decorator, Component, Node } from 'cc';
328
+ import { BaseReference } from '../assets/core/BaseReference';
329
+ import { Bind, BindCollect, BindTable, BindViewModel, Ref, ViewModel } from '../assets/core/ViewModel';
330
+ import { SpriteFrame } from 'cc';
331
+ import { Label, RichText, ProgressBar, Sprite, EditBox, Toggle, Slider, ToggleContainer, Button } from 'cc';
332
+ import { YXCollectionView } from '../assets/lib/collectView/lib_collect/yx-collection-view';
333
+ import { TableView } from '../assets/lib/tableView/TableView';
334
+ import { math } from 'cc';
335
+ import { YXFlowLayout } from '../assets/lib/collectView/lib_collect/yx-flow-layout';
336
+ import { BaseViewModelData } from '../assets/core/BaseViewModelData';
337
+ const { ccclass, property } = _decorator; \n`
338
+ text += this.genCodeVmData(false)
339
+ const sx = this.genCodeBind(false, true)
340
+ const className = this.node.name
341
+
342
+ let iinterface = `I${className}Data`
343
+ const onload = `
344
+ //#region ✅ 初始化
345
+ onLoad(): void {
346
+
347
+ }
348
+
349
+ start() {
350
+ this.viewModel.loadData()
351
+ }
352
+
353
+ // ✅ 外部界面调用,刷新UI
354
+ public refreshUI(data: ${iinterface}) { super.refreshUI(data); }`
355
+ const classView = `
356
+ @ccclass('${className}')
357
+ export class ${className} extends ViewModel(BaseReference) {${sx.text}\n${onload}\n\n${sx.event}\n}`
358
+
359
+ text += classView
360
+
361
+
258
362
  Editor.Clipboard.write("text", text);
259
363
  console.log("已复制到剪切板");
260
364
  }
@@ -314,4 +418,22 @@ ${text}
314
418
  return typeMap[compType] ?? 'any'; // 默认 fallback
315
419
  }
316
420
 
421
+ getDataTypeByComponentTypeValue(compType: string) {
422
+ const typeMap: Record<string, string> = {
423
+ 'Label': '"文本"',
424
+ 'RichText': '"文本RichText"',
425
+ 'Sprite': 'null',
426
+ 'Button': 'true', // Button 通常绑定激活状态(true/false)
427
+ 'ProgressBar': '0', // 进度条应为 number (0~1)
428
+ 'Skeleton': 'null',
429
+ 'Slider': '0',
430
+ 'Toggle': 'true',
431
+ 'EditBox': '"文本EditBox"',
432
+ 'ToggleContainer': '0', // 通常绑定选中项索引
433
+ 'TableView': '[1,2,3,4,5]', // 列表数据一般为数组
434
+ 'YXCollectionView': '[1,2,3,4,5]'
435
+ };
436
+ return typeMap[compType] ?? 'any'; // 默认 fallback
437
+ }
438
+
317
439
  }
@@ -200,8 +200,8 @@ export function ViewModel<T extends new (...args: any[]) => Component>(Base: T)
200
200
  return class extends Base {
201
201
  // 绑定关系存储
202
202
  _bindings: { uiProp: string; dataPath: string }[] = [];
203
- viewModel: any
204
203
 
204
+ viewModel: any
205
205
  // 创建响应式数据
206
206
  _makeReactive<T extends object>(obj: T, pathPrefix: string): T {
207
207
  const self = this as any;
@@ -220,7 +220,6 @@ export function ViewModel<T extends new (...args: any[]) => Component>(Base: T)
220
220
  return value;
221
221
  },
222
222
  set(target, key: string, value: any) {
223
-
224
223
  // ✅ 跳过 $ 开头的属性:不触发响应式更新
225
224
  if (key.startsWith(skip)) {
226
225
  target[key] = value;
@@ -319,6 +318,7 @@ function updateStatus(data: IBindingData, com: Component, value: any, self: any)
319
318
  tempData.value = btn.node.active
320
319
  self.viewModel[sx] = tempData
321
320
  data.event?.(self)
321
+ self[`onClick_${sx}`]?.(btn)
322
322
  }
323
323
  com_btn['btnCall'] = btnCall
324
324
  com_btn.node.on(Button.EventType.CLICK, com_btn['btnCall'], self);
@@ -349,6 +349,7 @@ function updateStatus(data: IBindingData, com: Component, value: any, self: any)
349
349
  tempData.value = slider.progress
350
350
  self.viewModel[sx] = tempData
351
351
  data.event?.(self)
352
+ self[`onClick_${sx}`]?.(slider)
352
353
  }
353
354
  com_sld['slideCall'] = slideCall
354
355
  com_sld.node.on('slide', slideCall, self);
@@ -367,6 +368,7 @@ function updateStatus(data: IBindingData, com: Component, value: any, self: any)
367
368
  tempData.value = toggle.isChecked
368
369
  self.viewModel[sx] = tempData
369
370
  data.event?.(self)
371
+ self[`onClick_${sx}`]?.(toggle)
370
372
  }
371
373
  com_tg['toggleCall'] = toggleCall
372
374
  com_tg.node.on(Toggle.EventType.TOGGLE, toggleCall, self);
@@ -385,6 +387,7 @@ function updateStatus(data: IBindingData, com: Component, value: any, self: any)
385
387
  tempData.value = editbox.textLabel.string
386
388
  self.viewModel[sx] = tempData
387
389
  data.event?.(self)
390
+ self[`onClick_${sx}`]?.(editbox)
388
391
  }
389
392
  com_eb['ebCall'] = ebCall
390
393
  com_eb.node.on('text-changed', ebCall, self);
@@ -408,6 +411,7 @@ function updateStatus(data: IBindingData, com: Component, value: any, self: any)
408
411
  tempData.value = com_tgc.toggleItems.indexOf(toggle)
409
412
  self.viewModel[sx] = tempData
410
413
  data.event?.(self)
414
+ self[`onClick_${sx}`]?.(toggle)
411
415
  }
412
416
  com_tgc.checkEvents.push(clickEventHandler);
413
417
  }
@@ -536,7 +540,7 @@ export function Ref(target: any, propertyKey: string) {
536
540
  this.initReferenceCollector();
537
541
  this.defineProperty(propertyKey);
538
542
  originalOnLoad?.call(this);
539
-
543
+ this.onLoadFinish();
540
544
  };
541
545
  }
542
546
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cc-component/cc-ex-component",
3
- "version": "1.1.8",
3
+ "version": "1.1.9",
4
4
  "engine": ">=3.8.6",
5
5
  "description": "系统组件添加常用扩展方法",
6
6
  "main": "index.ts",