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

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,19 @@ 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
+
70
+ isComDebug = false
58
71
 
59
72
  @property({ type: CollectorNodeData, readonly: false })
60
73
  private _nodes: CollectorNodeData[] = [];
@@ -66,6 +79,8 @@ export class ReferenceComponent extends Component {
66
79
  private _nodeMap: Map<string, Node | Sprite> = new Map();
67
80
 
68
81
  comList = ["EditBox", "Toggle", "ToggleContainer", "Slider", "Button", "ProgressBar", "YXCollectionView", "TableView"]
82
+ comList2 = ["YXCollectionView", "TableView"]
83
+ comList_base = ["EditBox", "Toggle", "ToggleContainer", "Slider", "Button", "ProgressBar"]
69
84
 
70
85
  protected onLoad(): void {
71
86
  if (EDITOR_NOT_IN_PREVIEW) {//处理编辑器逻辑
@@ -175,16 +190,27 @@ export class ReferenceComponent extends Component {
175
190
  }
176
191
 
177
192
  /** 生成引用节点的获取代码 并复制到剪切板 */
178
- private genCodeBind(isVm: boolean = true) {
193
+ private genCodeBind(isCopy: boolean = true, isClass: boolean = false) {
179
194
  if (!EDITOR_NOT_IN_PREVIEW) return;
180
195
  let text = "";
181
-
182
-
183
- const viewModel = `
184
- // 使用新装饰器(自动响应式 + 路径推导)
185
- @BindViewModel(new ViewModelData())
186
- viewModel: ViewModelData;`
187
- text += viewModel + "\n"
196
+ let eventStr: string = " //#region ✅ 事件"
197
+ let pix = "onClick_"
198
+ // const com = this.node.components.find(v => { return v.reference })
199
+ // const match = com.name.match(/<([^>]+)>/);
200
+ // const className = match && match[1] ? match[1] : "any"
201
+ const className = this.node.name
202
+ let data = `${className}Data`
203
+ let iinterface = `I${className}Data`
204
+ //console.error("[MLogger Error]", className)
205
+ const viewModel = `
206
+ // ✅ 外部界面调用,刷新UI
207
+ public refreshUI(data: ${iinterface}) { super.refreshUI(data); }
208
+
209
+ //#region ✅ 使用新装饰器(自动响应式 + 路径推导)
210
+ @BindViewModel(new ${className}Data())
211
+ viewModel: ${className}Data;`
212
+ text += viewModel + "\n\n"
213
+ text += ` //#region ✅ UI属性`
188
214
  //生成get属性
189
215
  this.nodes.forEach(data => {
190
216
  let key = data.key;
@@ -192,19 +218,19 @@ export class ReferenceComponent extends Component {
192
218
  let name = key[0].toLowerCase() + key.substring(1);
193
219
  const type = this.getPropertyType(data.com)
194
220
  let bind_pix = `@Bind`
195
- let event = `,{ event: (self) => { } }`
221
+ let event = `,{ event: (self:${className}) => { } }`
196
222
  if (type === "YXCollectionView") {
197
223
  event = `, {
198
- layout: (self) => {
224
+ layout: (self:${className}) => {
199
225
  const layout = new YXFlowLayout();
200
226
  layout.horizontalSpacing = 10;
201
227
  layout.verticalSpacing = 20;
202
228
  layout.itemSize = () => math.size(100, 100);
203
229
  return layout;
204
230
  },
205
- cellForItemAt: (self, indexPath, collectionView) => {
206
- let node = collectionView.dequeueReusableCell("cell", indexPath);
207
- // TODO: configure cell
231
+ cellForItemAt: (self:${className}, indexPath, collectionView) => {
232
+ const node = collectionView.dequeueReusableCell("cell", indexPath);
233
+ //node.getComponent(TableVIewItem).refreshUI(self.viewModel.${name}[indexPath.row])
208
234
  return node;
209
235
  },
210
236
  }`
@@ -213,8 +239,9 @@ export class ReferenceComponent extends Component {
213
239
  } else if (type === "TableView") {
214
240
  event = `, {
215
241
  itemSize: () => math.size(100, 100),
216
- cellForItemAt: (self, indexPath, collectionView) => {
217
- let node = collectionView.dequeueReusableCell("cell", indexPath)
242
+ cellForItemAt: (self:${className}, indexPath, collectionView) => {
243
+ const node = collectionView.dequeueReusableCell("cell", indexPath)
244
+ //node.getComponent(TableVIewItem).refreshUI(self.viewModel.${name}[indexPath.row])
218
245
  return node
219
246
  },
220
247
  }`
@@ -222,20 +249,42 @@ export class ReferenceComponent extends Component {
222
249
  }
223
250
 
224
251
  let bind = `${bind_pix}("${name}"${this.comList.includes(type) ? event : ""})`
252
+ if (isClass) {
253
+ bind = `${bind_pix}("${name}"${this.comList2.includes(type) ? event : ""})`
254
+ }
255
+ if (this.comList_base.includes(type)) {
256
+
257
+ eventStr += `
258
+ ${pix}${name}(comp: ${type === "ToggleContainer" ? "Toggle" : type}) {
259
+
260
+ }\n`
261
+
262
+ }
225
263
  //@ts-ignore
226
264
  let line = ` ${bind} @Ref ${name}: ${type};`
227
265
  text += line;
228
266
  });
229
267
 
230
268
 
231
- Editor.Clipboard.write("text", text);
232
- console.log("已复制到剪切板");
269
+ if (isCopy) {
270
+ Editor.Clipboard.write("text", text);
271
+ console.log("已复制到剪切板");
272
+ }
273
+ return { text: text, event: eventStr }
274
+
233
275
  }
234
276
 
235
277
  /** 生成引用节点的获取代码 并复制到剪切板 */
236
- private genCodeVmData() {
278
+ private genCodeVmData(isCopy: boolean = true) {
237
279
  if (!EDITOR_NOT_IN_PREVIEW) return;
238
280
  let text = ""
281
+ let sx_this = ''
282
+ let sx = ' \n'
283
+ const className = this.node.name
284
+
285
+ let data = `${className}Data`
286
+ let iinterface = `I${className}Data`
287
+
239
288
  //生成get属性
240
289
  this.nodes.forEach(data => {
241
290
  let key = data.key;
@@ -243,22 +292,87 @@ export class ReferenceComponent extends Component {
243
292
  const type = this.getPropertyType(data.com)
244
293
  //@ts-ignore
245
294
  let line = ` ${name}: ${this.getDataTypeByComponentType(type)};`//`private get ${name}() { return this.rc.get("${key}", ${this.getPropertyType(data.node)}); }`;
246
- text += line + "\n";
295
+ sx += line + "\n";
296
+
297
+ let line_sx = ` this.${name} = ${this.getDataTypeByComponentTypeValue(type)}`
298
+ sx_this += line_sx + '\n'
247
299
  });
248
300
 
249
301
  text = `
250
- class ViewModelData {
251
- ${text}
302
+ //#region 数据接口
303
+ export interface ${iinterface} {
304
+ ${sx}
305
+ }
306
+ `;
307
+ text += `
308
+ //#region ✅ 数据VM
309
+ class ${data} extends BaseViewModelData implements ${iinterface} {
310
+ ${sx}
252
311
 
312
+ // ✅ 本界面内部调用
253
313
  loadData() {
254
-
314
+ ${sx_this}
255
315
  }
256
316
  }
257
317
  `;
318
+ if (isCopy) {
319
+ Editor.Clipboard.write("text", text);
320
+ console.log("已复制到剪切板");
321
+ }
322
+ return text
323
+ }
324
+
325
+
326
+
327
+
328
+
329
+ /** 生成引用节点的获取代码 并复制到剪切板 */
330
+ private genCodeVmDataAll() {
331
+ if (!EDITOR_NOT_IN_PREVIEW) return;
332
+ let importStr = `
333
+ import { Label, RichText, ProgressBar, Sprite, EditBox, Toggle, Slider, ToggleContainer, Button, math, SpriteFrame, _decorator } from 'cc';
334
+ import { ViewModel, BindViewModel, BindTable, BindCollect, Bind, Ref, BaseViewModelData, YXCollectionView, YXFlowLayout, TableView, BaseReference } from 'db://assets/pkg-export/@cc-component/cc-ex-component';
335
+ const { ccclass, property } = _decorator;`
336
+
337
+ if (this.isComDebug) {
338
+ importStr = `
339
+ import { _decorator, SpriteFrame, Label, RichText, ProgressBar, Sprite, EditBox, Toggle, Slider, ToggleContainer, Button, math } from 'cc';
340
+ import { BaseReference } from '../assets/core/BaseReference';
341
+ import { BaseViewModelData } from '../assets/core/BaseViewModelData';
342
+ import { ViewModel, BindViewModel, Bind, Ref, BindTable, BindCollect } from '../assets/core/ViewModel';
343
+ import { YXCollectionView } from '../assets/lib/collectView/lib_collect/yx-collection-view';
344
+ import { YXFlowLayout } from '../assets/lib/collectView/lib_collect/yx-flow-layout';
345
+ import { TableView } from '../assets/lib/tableView/TableView';
346
+ const { ccclass, property } = _decorator;
347
+ `
348
+ }
349
+ let text = `${importStr}\n`
350
+ text += this.genCodeVmData(false)
351
+ const sx = this.genCodeBind(false, true)
352
+ const className = this.node.name
353
+
354
+ let iinterface = `I${className}Data`
355
+ const onload = `
356
+ //#region ✅ 初始化
357
+ onLoad(): void {
358
+
359
+ }
360
+
361
+ start() {
362
+ this.viewModel.loadData()
363
+ }`
364
+ const classView = `
365
+ @ccclass('${className}')
366
+ export class ${className} extends ViewModel(BaseReference) {${sx.text}\n${onload}\n\n${sx.event}\n}`
367
+
368
+ text += classView
369
+
370
+
258
371
  Editor.Clipboard.write("text", text);
259
372
  console.log("已复制到剪切板");
260
373
  }
261
374
 
375
+
262
376
  /** 获取属性类型名字 */
263
377
  private getPropertyType(node: Node) {
264
378
  if (!EDITOR_NOT_IN_PREVIEW) return;
@@ -314,4 +428,22 @@ ${text}
314
428
  return typeMap[compType] ?? 'any'; // 默认 fallback
315
429
  }
316
430
 
431
+ getDataTypeByComponentTypeValue(compType: string) {
432
+ const typeMap: Record<string, string> = {
433
+ 'Label': '"文本"',
434
+ 'RichText': '"文本RichText"',
435
+ 'Sprite': 'null',
436
+ 'Button': 'true', // Button 通常绑定激活状态(true/false)
437
+ 'ProgressBar': '0', // 进度条应为 number (0~1)
438
+ 'Skeleton': 'null',
439
+ 'Slider': '0',
440
+ 'Toggle': 'true',
441
+ 'EditBox': '"文本EditBox"',
442
+ 'ToggleContainer': '0', // 通常绑定选中项索引
443
+ 'TableView': '[1,2,3,4,5]', // 列表数据一般为数组
444
+ 'YXCollectionView': '[1,2,3,4,5]'
445
+ };
446
+ return typeMap[compType] ?? 'any'; // 默认 fallback
447
+ }
448
+
317
449
  }
@@ -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.2.0",
4
4
  "engine": ">=3.8.6",
5
5
  "description": "系统组件添加常用扩展方法",
6
6
  "main": "index.ts",