@cc-component/cc-ex-component 1.1.6 → 1.1.7

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.
Files changed (80) hide show
  1. package/assets/core/BaseReference.ts +40 -0
  2. package/assets/{video/VideoComponent.ts.meta → core/BaseReference.ts.meta} +1 -1
  3. package/assets/core/BaseViewModelData.ts +12 -0
  4. package/assets/{video/Interface.ts.meta → core/BaseViewModelData.ts.meta} +1 -1
  5. package/assets/core/ReferenceComponent.ts +317 -0
  6. package/assets/core/ViewModel.ts +542 -0
  7. package/assets/{video/IVideo.ts.meta → core/ViewModel.ts.meta} +9 -9
  8. package/assets/ex/EXButton.ts +191 -0
  9. package/assets/ex/EXButton.ts.meta +9 -0
  10. package/assets/ex/ExCommon.ts +6 -4
  11. package/assets/ex/ExTool.ts +116 -0
  12. package/assets/ex/ExTool.ts.meta +9 -0
  13. package/assets/lib/collectView/lib-ext/custom-grid-flow-layout.ts +105 -0
  14. package/assets/lib/collectView/lib-ext/custom-grid-flow-layout.ts.meta +9 -0
  15. package/assets/lib/collectView/lib-ext/horizontal-center-layout.ts +84 -0
  16. package/assets/lib/collectView/lib-ext/horizontal-center-layout.ts.meta +9 -0
  17. package/assets/lib/collectView/lib-ext/yx-card-page-layout.ts +132 -0
  18. package/assets/lib/collectView/lib-ext/yx-card-page-layout.ts.meta +9 -0
  19. package/assets/lib/collectView/lib-ext/yx-carousel-layout.ts +156 -0
  20. package/assets/lib/collectView/lib-ext/yx-carousel-layout.ts.meta +9 -0
  21. package/assets/lib/collectView/lib-ext/yx-cover-layout.ts +405 -0
  22. package/assets/lib/collectView/lib-ext/yx-cover-layout.ts.meta +9 -0
  23. package/assets/lib/collectView/lib-ext/yx-masonry-flow-layout.ts +194 -0
  24. package/assets/lib/collectView/lib-ext/yx-masonry-flow-layout.ts.meta +9 -0
  25. package/assets/lib/collectView/lib-ext/yx-page-view.ts +232 -0
  26. package/assets/lib/collectView/lib-ext/yx-page-view.ts.meta +9 -0
  27. package/assets/lib/collectView/lib-ext/yx-table-view.ts +159 -0
  28. package/assets/lib/collectView/lib-ext/yx-table-view.ts.meta +9 -0
  29. package/assets/lib/collectView/lib-ext.meta +9 -0
  30. package/assets/lib/collectView/lib_collect/yx-collection-view.ts +1549 -0
  31. package/assets/lib/collectView/lib_collect/yx-collection-view.ts.meta +9 -0
  32. package/assets/lib/collectView/lib_collect/yx-compact-flow-layout.ts +364 -0
  33. package/assets/lib/collectView/lib_collect/yx-compact-flow-layout.ts.meta +9 -0
  34. package/assets/lib/collectView/lib_collect/yx-flow-layout.ts +909 -0
  35. package/assets/lib/collectView/lib_collect/yx-flow-layout.ts.meta +9 -0
  36. package/assets/lib/collectView/lib_collect/yx-table-layout.ts +352 -0
  37. package/assets/lib/collectView/lib_collect/yx-table-layout.ts.meta +9 -0
  38. package/assets/lib/collectView/lib_collect.meta +9 -0
  39. package/assets/{video/list.meta → lib/collectView.meta} +9 -9
  40. package/assets/lib/tableView/IListView.ts +17 -0
  41. package/assets/lib/tableView/IListView.ts.meta +9 -0
  42. package/assets/lib/tableView/ListView.ts +197 -0
  43. package/assets/lib/tableView/ListView.ts.meta +9 -0
  44. package/assets/lib/tableView/ListViewPage.ts +1048 -0
  45. package/assets/lib/tableView/ListViewPage.ts.meta +9 -0
  46. package/assets/lib/tableView/ListViewPageLoop.ts +922 -0
  47. package/assets/lib/tableView/ListViewPageLoop.ts.meta +1 -0
  48. package/assets/lib/tableView/TableView.ts +82 -0
  49. package/assets/lib/tableView/TableView.ts.meta +9 -0
  50. package/assets/lib/tableView.meta +9 -0
  51. package/assets/{video.meta → lib.meta} +1 -1
  52. package/assets/platform/Interface.ts +15 -10
  53. package/assets/platform/android/AndroidModule.ts +12 -0
  54. package/assets/platform/android/AndroidModule.ts.meta +9 -0
  55. package/assets/platform/android/AndroidSDK.ts +1 -2
  56. package/assets/platform/base/PlatfprmModule.ts +44 -29
  57. package/assets/platform/base/SDKBase.ts +2 -2
  58. package/assets/platform/base/TTSDK.ts +21 -10
  59. package/assets/platform/base/WXSDK.ts +15 -16
  60. package/assets/platform/wx/MiniSDK.ts +41 -3
  61. package/assets/platform/wx/wxmini.d.ts +2 -2
  62. package/index.ts +0 -1
  63. package/package.json +1 -1
  64. package/assets/core/ReferenceCollector.ts +0 -172
  65. package/assets/video/IVideo.ts +0 -73
  66. package/assets/video/Interface.ts +0 -25
  67. package/assets/video/VideoComponent.prefab +0 -614
  68. package/assets/video/VideoComponent.prefab.meta +0 -13
  69. package/assets/video/VideoComponent.ts +0 -33
  70. package/assets/video/VideoManager.ts +0 -399
  71. package/assets/video/VideoManager.ts.meta +0 -9
  72. package/assets/video/VideoModule.ts +0 -137
  73. package/assets/video/VideoModule.ts.meta +0 -9
  74. package/assets/video/VideoPlayTT.ts +0 -338
  75. package/assets/video/VideoPlayTT.ts.meta +0 -9
  76. package/assets/video/VideoPlayWX.ts +0 -274
  77. package/assets/video/VideoPlayWX.ts.meta +0 -9
  78. package/assets/video/VideoPlayWeb.ts +0 -228
  79. package/assets/video/VideoPlayWeb.ts.meta +0 -9
  80. /package/assets/core/{ReferenceCollector.ts.meta → ReferenceComponent.ts.meta} +0 -0
@@ -0,0 +1,542 @@
1
+ // assets/cc-ex-component/core/DataBinding.ts
2
+ import { Label } from 'cc';
3
+ import { sp } from 'cc';
4
+ import { Sprite } from 'cc';
5
+ import { ToggleContainer } from 'cc';
6
+ import { Size } from 'cc';
7
+ import { EventHandler } from 'cc';
8
+ import { EditBox, Toggle, Slider, Button, ProgressBar, Node } from 'cc';
9
+ import { RichText } from 'cc';
10
+ import { Component } from 'cc';
11
+ import { js } from 'cc';
12
+ import { escape } from 'querystring';
13
+ import { IIndexPath } from '../lib/tableView/IListView';
14
+ import { ListView } from '../lib/tableView/ListView';
15
+ import { TableView } from '../lib/tableView/TableView';
16
+ import { YXFlowLayout } from '../lib/collectView/lib_collect/yx-flow-layout';
17
+ import { math } from 'cc';
18
+ import { YXCollectionView, YXIndexPath } from '../lib/collectView/lib_collect/yx-collection-view';
19
+
20
+ interface IBindingData extends ITableViewEvents, IBindingDataEvents {
21
+ dataPath: string;
22
+ type: any;
23
+ // 允许任意额外属性
24
+ [key: string]: any;
25
+ }
26
+
27
+
28
+ interface IBindingDataEvents {
29
+ reset?: Function;
30
+ event?: Function;
31
+ }
32
+
33
+
34
+ interface ITableViewEvents {
35
+ /**列表相关 */
36
+ itemSize: (self: any) => Size,
37
+ cellForItemAt: (self: any, indexPath: IIndexPath, collectionView: ListView) => Node,
38
+ onTouchCellAt?: (self: any, indexPath: IIndexPath) => void
39
+ numberOfItems?: (self: any) => number;
40
+ moveFinish?: (self: any, indexPath: IIndexPath) => void
41
+
42
+ }
43
+
44
+ interface ICollectViewEvents {
45
+ /**列表相关 */
46
+ layout: (self: any) => YXFlowLayout,
47
+ cellForItemAt: (self: any, indexPath: YXIndexPath, collectionView: YXCollectionView) => Node
48
+ itemSize?: ((self: any, indexPath: YXIndexPath, layout: YXFlowLayout, collectionView: YXCollectionView) => math.Size),
49
+ onTouchCellAt?: (self: any, indexPath: YXIndexPath) => void
50
+ numberOfItems?: ((self: any, section: number, collectionView: YXCollectionView) => number);
51
+ }
52
+
53
+ // 全局存储绑定关系: { className -> { uiProp: dataPath } }
54
+ const bindingMap = new Map<string, Map<string, IBindingData>>();
55
+ const baseData = 'viewModel'
56
+ const skip = "$"
57
+ // const comType = {
58
+ // "cc.Sprite": typeof Sprite,
59
+ // "cc.Label": Label,
60
+ // "cc.RichText": RichText,
61
+ // "cc.Skeleton": sp.Skeleton,
62
+
63
+ // "cc.EditBox": EditBox,
64
+ // "cc.ProgressBar": ProgressBar,
65
+
66
+ // "cc.Slider": Slider,
67
+ // "cc.Toggle": Toggle,
68
+ // "cc.Button": Button,
69
+ // }
70
+
71
+ /**
72
+ * 数据绑定装饰器
73
+ * @param dataPath 数据路径(如 "data.name")
74
+ * @param reset 重写赋值方法,自定义实现. 参数:(self 组件所在的父类,com 组件,value 值)
75
+ * @param event 点击事件,滑动事件,等等. 参数:(self 组件所在的父类)
76
+ */
77
+ export function Bind<T extends Component>(dataPath: string, param?: IBindingDataEvents) {
78
+ dataPath = baseData + '.' + dataPath;
79
+ return function (target: any, propertyKey: string) {
80
+ const className = js.getClassName(target.constructor);
81
+ if (!bindingMap.has(className)) {
82
+ bindingMap.set(className, new Map());
83
+ }
84
+ const data: IBindingData = {
85
+ dataPath: dataPath, type: null, reset: param?.reset, event: param?.event,
86
+ itemSize: null,
87
+ cellForItemAt: null,
88
+ numberOfItems: function (): number {
89
+ throw new Error('Function not implemented.');
90
+ }
91
+ }
92
+
93
+ bindingMap.get(className)!.set(propertyKey, data);
94
+ // 重写 onLoad 以初始化绑定
95
+ const originalOnLoad = target.constructor.prototype.onLoad;
96
+ target.constructor.prototype.onLoad = function () {
97
+ originalOnLoad?.call(this);
98
+ const com = this[propertyKey];
99
+ const classname = js.getClassName(com)
100
+ data.type = classname;
101
+ bindingMap.get(className)!.set(propertyKey, data);
102
+ // 初始化 UI
103
+ const value = this._getNestedValue(this, dataPath);
104
+ if (com) {
105
+ updateStatus(data, com, value, this)
106
+ }
107
+
108
+ // 记录绑定关系到实例
109
+ if (!this._bindings) this._bindings = [];
110
+ this._bindings.push({ uiProp: propertyKey, dataPath });
111
+ };
112
+ };
113
+ }
114
+
115
+ export function BindTable<T extends Component>(dataPath: string, param?: ITableViewEvents) {
116
+ dataPath = baseData + '.' + dataPath;
117
+ return function (target: any, propertyKey: string) {
118
+ const className = js.getClassName(target.constructor);
119
+ if (!bindingMap.has(className)) {
120
+ bindingMap.set(className, new Map());
121
+ }
122
+ const data: IBindingData = {
123
+ dataPath: dataPath, type: null,
124
+ itemSize: param.itemSize,
125
+ cellForItemAt: param.cellForItemAt,
126
+ numberOfItems: param.numberOfItems,
127
+ onTouchCellAt: param.onTouchCellAt,
128
+ moveFinish: param.moveFinish,
129
+ }
130
+
131
+ bindingMap.get(className)!.set(propertyKey, data);
132
+ // 重写 onLoad 以初始化绑定
133
+ const originalOnLoad = target.constructor.prototype.onLoad;
134
+ target.constructor.prototype.onLoad = function () {
135
+ originalOnLoad?.call(this);
136
+ const com = this[propertyKey];
137
+ const classname = js.getClassName(com)
138
+ data.type = classname;
139
+ bindingMap.get(className)!.set(propertyKey, data);
140
+ // 初始化 UI
141
+ const value = this._getNestedValue(this, dataPath);
142
+ if (com) {
143
+ updateStatus(data, com, value, this)
144
+ }
145
+
146
+ // 记录绑定关系到实例
147
+ if (!this._bindings) this._bindings = [];
148
+ this._bindings.push({ uiProp: propertyKey, dataPath });
149
+ };
150
+ };
151
+ }
152
+
153
+ export function BindCollect<T extends Component>(dataPath: string, param?: ICollectViewEvents) {
154
+ dataPath = baseData + '.' + dataPath;
155
+ return function (target: any, propertyKey: string) {
156
+ const className = js.getClassName(target.constructor);
157
+ if (!bindingMap.has(className)) {
158
+ bindingMap.set(className, new Map());
159
+ }
160
+
161
+ const data: IBindingData = {
162
+ dataPath: dataPath, type: null,
163
+ layout: param.layout,
164
+ cellForItemAt: param.cellForItemAt as any,
165
+ numberOfItems: param.numberOfItems as any,
166
+ itemSize: param.itemSize as any,
167
+ onTouchCellAt: param.onTouchCellAt,
168
+ }
169
+
170
+ // layout: (self: any) => YXFlowLayout,
171
+ // cellForItemAt: (self: any, indexPath: YXIndexPath, collectionView: YXCollectionView) => Node
172
+ // itemSize?: ((self: any, indexPath: YXIndexPath, layout: YXFlowLayout, collectionView: YXCollectionView) => math.Size),
173
+ // onTouchCellAt?: (self: any, indexPath: YXIndexPath) => void
174
+ // numberOfItems?: ((self: any, section: number, collectionView: YXCollectionView) => number);
175
+ bindingMap.get(className)!.set(propertyKey, data);
176
+ // 重写 onLoad 以初始化绑定
177
+ const originalOnLoad = target.constructor.prototype.onLoad;
178
+ target.constructor.prototype.onLoad = function () {
179
+ originalOnLoad?.call(this);
180
+ const com = this[propertyKey];
181
+ const classname = js.getClassName(com)
182
+ data.type = classname;
183
+ bindingMap.get(className)!.set(propertyKey, data);
184
+ // 初始化 UI
185
+ const value = this._getNestedValue(this, dataPath);
186
+ if (com) {
187
+ updateStatus(data, com, value, this)
188
+ }
189
+
190
+ // 记录绑定关系到实例
191
+ if (!this._bindings) this._bindings = [];
192
+ this._bindings.push({ uiProp: propertyKey, dataPath });
193
+ };
194
+ };
195
+ }
196
+ /**
197
+ * 响应式绑定 Mixin(混入方法)
198
+ */
199
+ export function ViewModel<T extends new (...args: any[]) => Component>(Base: T) {
200
+ return class extends Base {
201
+ // 绑定关系存储
202
+ _bindings: { uiProp: string; dataPath: string }[] = [];
203
+ viewModel: any
204
+
205
+ // 创建响应式数据
206
+ _makeReactive<T extends object>(obj: T, pathPrefix: string): T {
207
+ const self = this as any;
208
+ return new Proxy(obj, {
209
+ get(target, key: string) {
210
+ // ✅ 跳过 $ 开头的属性:直接返回原始值,不代理
211
+ if (key.startsWith(skip)) {
212
+ return target[key];
213
+ }
214
+ const value = target[key];
215
+ //暂时不循环找对象
216
+ // if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
217
+ // console.log(`get ${pathPrefix}----${key}`);
218
+ // return self._makeReactive(value, `${pathPrefix}.${key}`);
219
+ // }
220
+ return value;
221
+ },
222
+ set(target, key: string, value: any) {
223
+
224
+ // ✅ 跳过 $ 开头的属性:不触发响应式更新
225
+ if (key.startsWith(skip)) {
226
+ target[key] = value;
227
+ return true;
228
+ }
229
+ else if (value?.skip) {
230
+ target[key] = value.value;
231
+ return true;
232
+ }
233
+ const fullPath = `${pathPrefix}.${key}`;
234
+ target[key] = value;
235
+ self._onDataChange?.(fullPath, value);
236
+ return true;
237
+ }
238
+ });
239
+ }
240
+
241
+ // 获取嵌套值
242
+ _getNestedValue(obj: any, path: string) {
243
+ return path.split('.').reduce((current, key) => current?.[key], obj);
244
+ }
245
+
246
+ // 数据变化回调(可被子类 override)
247
+ _onDataChange(fullPath: string, newValue: any) {
248
+ if (!this._bindings) return;
249
+ this._bindings.forEach(({ uiProp, dataPath }) => {
250
+ if (fullPath === dataPath) {
251
+ const com = this[uiProp]
252
+ if (com) {
253
+ const classname = js.getClassName(this)
254
+ const data = bindingMap.get(classname).get(uiProp)
255
+ const value = this._getNestedValue(this, data.dataPath);
256
+ updateStatus(data, com, value, this)
257
+ }
258
+ }
259
+ });
260
+ }
261
+
262
+ /** 解除当前组件的所有数据绑定 */
263
+ public unbindViewModel(): void {
264
+ // 1. 清空绑定关系(停止 _onDataChange 触发 UI 更新)
265
+ this._bindings = [];
266
+ // 2. 替换 data 为普通对象(破坏 Proxy 响应式)
267
+ this.viewModel = null
268
+
269
+ }
270
+
271
+ // 在 withDataBinding 返回的 class 中
272
+ protected onDestroy(): void {
273
+ this.unbindViewModel();
274
+ super.onDestroy?.();
275
+ }
276
+
277
+
278
+ };
279
+ }
280
+
281
+ function updateStatus(data: IBindingData, com: Component, value: any, self: any) {
282
+
283
+ const sx = data.dataPath.split('.').pop();
284
+ const tempData = { value: value, skip: false }
285
+ switch (data.type) {
286
+ case 'cc.Label':
287
+ if (data.reset) {
288
+ data.reset(self, value, com);
289
+ } else {
290
+ if (value) (com as Label).string = value?.toString() || '';
291
+ }
292
+ break;
293
+ case 'cc.RichText':
294
+ if (data.reset) {
295
+ data.reset(self, value, com);
296
+ } else
297
+ if (value)
298
+ (com as RichText).string = value?.toString() || '';
299
+ break;
300
+ case 'cc.Sprite':
301
+ // 假设 value 是 SpriteFrame 路径或资源
302
+ // 需要额外处理资源加载逻辑
303
+ if (data.reset) {
304
+ data.reset(self, value, com);
305
+ } else
306
+ if (value) (com as Sprite).spriteFrame = value;
307
+ break;
308
+ case 'cc.Button':
309
+ const com_btn = (com as Button);
310
+ if (data.reset) {
311
+ data.reset(self, value, com);
312
+ } else
313
+ com_btn.node.active = value ?? true;
314
+
315
+ //事件
316
+ com_btn.node.off(Button.EventType.CLICK, com_btn['btnCall'], self);
317
+ tempData.skip = true;
318
+ const btnCall = (btn) => {
319
+ tempData.value = btn.node.active
320
+ self.viewModel[sx] = tempData
321
+ data.event?.(self)
322
+ }
323
+ com_btn['btnCall'] = btnCall
324
+ com_btn.node.on(Button.EventType.CLICK, com_btn['btnCall'], self);
325
+ break;
326
+ case 'cc.ProgressBar':
327
+ if (data.reset) {
328
+ data.reset(self, value, com);
329
+ } else
330
+ if (value) (com as ProgressBar).progress = Number(value) || 0;
331
+ break;
332
+ case 'cc.Skeleton':
333
+ if (data.reset) {
334
+ data.reset(self, value, com);
335
+ } else
336
+ if (value) (com as sp.Skeleton).skeletonData = value
337
+ break;
338
+ case 'cc.Slider':
339
+ const com_sld = (com as Slider);
340
+ if (data.reset) {
341
+ data.reset(self, value, com);
342
+ } else
343
+ if (value) com_sld.progress = Number(value) || 0;
344
+
345
+ //事件
346
+ com_sld.node.off("slide", com_sld['slideCall'], self)
347
+ tempData.skip = true;
348
+ const slideCall = (slider) => {
349
+ tempData.value = slider.progress
350
+ self.viewModel[sx] = tempData
351
+ data.event?.(self)
352
+ }
353
+ com_sld['slideCall'] = slideCall
354
+ com_sld.node.on('slide', slideCall, self);
355
+ break;
356
+ case 'cc.Toggle':
357
+ const com_tg = (com as Toggle);
358
+ if (data.reset) {
359
+ data.reset(self, value, com);
360
+ } else
361
+ if (value) com_tg.isChecked = Boolean(value);
362
+
363
+ //事件
364
+ com_tg.node.off(Toggle.EventType.TOGGLE, com_tg['toggleCall'], self)
365
+ tempData.skip = true;
366
+ const toggleCall = (toggle) => {
367
+ tempData.value = toggle.isChecked
368
+ self.viewModel[sx] = tempData
369
+ data.event?.(self)
370
+ }
371
+ com_tg['toggleCall'] = toggleCall
372
+ com_tg.node.on(Toggle.EventType.TOGGLE, toggleCall, self);
373
+ break;
374
+ case 'cc.EditBox':
375
+ const com_eb = (com as EditBox);
376
+ if (data.reset) {
377
+ data.reset(self, value, com);
378
+ } else
379
+ if (value) com_eb.string = value?.toString() || '';
380
+
381
+ //事件
382
+ com_eb.node.off("text-changed", com_eb['ebCall'], self)
383
+ tempData.skip = true;
384
+ const ebCall = (editbox: EditBox) => {
385
+ tempData.value = editbox.textLabel.string
386
+ self.viewModel[sx] = tempData
387
+ data.event?.(self)
388
+ }
389
+ com_eb['ebCall'] = ebCall
390
+ com_eb.node.on('text-changed', ebCall, self);
391
+ break;
392
+ case 'cc.ToggleContainer':
393
+ {
394
+ const com_tgc = (com as ToggleContainer);
395
+ if (data.reset) {
396
+ data.reset(self, value, com);
397
+ }
398
+
399
+ //事件
400
+ if (com_tgc.checkEvents.length <= 0) {
401
+ const funcName = "onClick_ToggleContainer"
402
+ const clickEventHandler = new EventHandler();
403
+ clickEventHandler.target = self.node; // 这个 node 节点是你的事件处理代码组件所属的节点
404
+ clickEventHandler.component = js.getClassName(self)//delegate.constructor.name;// 这个是脚本类名
405
+ clickEventHandler.handler = funcName
406
+ self[funcName] = (toggle: Toggle) => {
407
+ tempData.skip = true;
408
+ tempData.value = com_tgc.toggleItems.indexOf(toggle)
409
+ self.viewModel[sx] = tempData
410
+ data.event?.(self)
411
+ }
412
+ com_tgc.checkEvents.push(clickEventHandler);
413
+ }
414
+ const tg = com_tgc.toggleItems[value]
415
+ if (tg)
416
+ tg.isChecked = true;
417
+
418
+ }
419
+ break;
420
+
421
+ case 'TableView':
422
+ {
423
+
424
+ const com_list = (com as TableView);
425
+ if (data.reset) { data.reset(self, value, com); }
426
+
427
+ // ✅ 关键:不要缓存 count,而是通过 dataPath 动态取值
428
+ const getLatestDataLength = () => {
429
+ const latestValue = self._getNestedValue(self, data.dataPath);
430
+ return Array.isArray(latestValue) ? latestValue.length : 0;
431
+ };
432
+
433
+ if (com_list.isInit) {
434
+ com_list.reload()
435
+ } else {
436
+ const cellForItemAt = (indexPath: IIndexPath, collectionView: ListView) => {
437
+ return data.cellForItemAt(self, indexPath, collectionView);
438
+ }
439
+ const numberOfItems = () => {
440
+ return getLatestDataLength()
441
+ }
442
+ const itemSize = () => {
443
+ return data.itemSize(self)
444
+ }
445
+ const moveFinish = (indexPath: IIndexPath) => {
446
+ data.moveFinish?.(self, indexPath)
447
+ }
448
+ const onTouchCellAt = (indexPath: IIndexPath) => {
449
+ data.onTouchCellAt?.(self, indexPath)
450
+ }
451
+
452
+ const classView = { cellForItemAt, numberOfItems, itemSize, moveFinish, onTouchCellAt }
453
+ com_list.onLoadFinish(() => {
454
+ com_list.init(classView);
455
+ com_list.reload()
456
+ })
457
+ }
458
+ }
459
+ break;
460
+
461
+ case 'YXCollectionView':
462
+ {
463
+ const com_list = (com as YXCollectionView);
464
+ // ✅ 关键:不要缓存 count,而是通过 dataPath 动态取值
465
+ const getLatestDataLength = () => {
466
+ const latestValue = self._getNestedValue(self, data.dataPath);
467
+ return Array.isArray(latestValue) ? latestValue.length : 0;
468
+ };
469
+ const table_collection = com_list
470
+
471
+ if (!table_collection.layout) {
472
+ const identifier = 'cell';
473
+ // 配置 layout 布局规则
474
+ // let layout = new YXFlowLayout()
475
+ // const column = 4
476
+ // layout.horizontalSpacing = 10
477
+ // layout.verticalSpacing = 10
478
+ // const width = 100
479
+ // const height = 163
480
+ // layout.itemSize = math.size(width, height)
481
+ table_collection.layout = data.layout()
482
+ // 注册列表内需要使用的 cell 节点类型
483
+ // 这个演示是通过编辑器绑定的,可以查看场景内 list 节点里的 register cells 配置
484
+ // this.table_collection.register('cell', () => instantiate('your cell prefab'))
485
+ // 确定列表内一共需要显示多少条内容
486
+ // table_collection.isCenterShow = false;//少于宽度,居中显示
487
+ table_collection.numberOfItems = () => getLatestDataLength()
488
+ table_collection.cellForItemAt = (indexPath, collectionView) => {
489
+ return data.cellForItemAt(self, indexPath, collectionView as any) // 返回这个节点给列表显示
490
+ }
491
+
492
+ table_collection.onTouchCellAt = (indexPath, collectionView) => {
493
+ // 通过 getVisibleNode 获取到点击的节点
494
+ //const cell = collectionView.getVisibleCellNode(indexPath)
495
+ data.onTouchCellAt?.(self, indexPath)
496
+ }
497
+ table_collection.onCellDisplay = (cell, indexPath) => { }
498
+ table_collection.onCellEndDisplay = (cell, indexPath) => { }
499
+ }
500
+ table_collection.reloadData()
501
+ }
502
+ break;
503
+ default:
504
+ console.error(`请检查类型: ${data.type}`);
505
+ }
506
+
507
+ }
508
+ // assets/cc-ex-component/core/ViewModel.ts
509
+
510
+ // ... 其他代码 ...
511
+
512
+ /**
513
+ * 响应式数据装饰器
514
+ * 自动将属性转为响应式对象,并使用属性名作为路径前缀
515
+ */
516
+ export function BindViewModel(initialValue?: any) {
517
+ return function (target: any, propertyKey: string) {
518
+ const originalOnLoad = target.constructor.prototype.onLoad;
519
+ target.constructor.prototype.onLoad = function () {
520
+ // 获取初始值(支持传入或默认空对象)
521
+ const initValue = typeof initialValue === 'function'
522
+ ? initialValue()
523
+ : (initialValue ?? {});
524
+ // 创建响应式对象
525
+ this[propertyKey] = this._makeReactive(initValue, propertyKey);
526
+ originalOnLoad?.call(this);
527
+
528
+ };
529
+ };
530
+ }
531
+
532
+ // 定义装饰器
533
+ export function Ref(target: any, propertyKey: string) {
534
+ const originalOnLoad = target.constructor.prototype.onLoad;
535
+ target.constructor.prototype.onLoad = function (this: any) {
536
+ this.initReferenceCollector();
537
+ this.defineProperty(propertyKey);
538
+ originalOnLoad?.call(this);
539
+
540
+ };
541
+ }
542
+
@@ -1,9 +1,9 @@
1
- {
2
- "ver": "4.0.24",
3
- "importer": "typescript",
4
- "imported": true,
5
- "uuid": "f52ed3a4-99e9-4583-a6e7-642a14237b86",
6
- "files": [],
7
- "subMetas": {},
8
- "userData": {}
9
- }
1
+ {
2
+ "ver": "4.0.24",
3
+ "importer": "typescript",
4
+ "imported": true,
5
+ "uuid": "91193c30-a004-4bca-bfc0-45fb594eea0f",
6
+ "files": [],
7
+ "subMetas": {},
8
+ "userData": {}
9
+ }