1e41f4b71Sopenharmony_ci# LazyForEach:数据懒加载 2e41f4b71Sopenharmony_ci 3e41f4b71Sopenharmony_ciAPI参数说明见:[LazyForEach API参数说明](../reference/apis-arkui/arkui-ts/ts-rendering-control-lazyforeach.md) 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ciLazyForEach从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。当在滚动容器中使用了LazyForEach,框架会根据滚动容器可视区域按需创建组件,当组件滑出可视区域外时,框架会进行组件销毁回收以降低内存占用。 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ci## 使用限制 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ci- LazyForEach必须在容器组件内使用,仅有[List](../reference/apis-arkui/arkui-ts/ts-container-list.md)、[Grid](../reference/apis-arkui/arkui-ts/ts-container-grid.md)、[Swiper](../reference/apis-arkui/arkui-ts/ts-container-swiper.md)以及[WaterFlow](../reference/apis-arkui/arkui-ts/ts-container-waterflow.md)组件支持数据懒加载(可配置cachedCount属性,即只加载可视部分以及其前后少量数据用于缓冲),其他组件仍然是一次性加载所有的数据。 10e41f4b71Sopenharmony_ci- 容器组件內使用LazyForEach的时候,只能包含一个LazyForEach。以List为例,同时包含ListItem、ForEach、LazyForEach的情形是不推荐的;同时包含多个LazyForEach也是不推荐的。 11e41f4b71Sopenharmony_ci- LazyForEach在每次迭代中,必须创建且只允许创建一个子组件;即LazyForEach的子组件生成函数有且只有一个根组件。 12e41f4b71Sopenharmony_ci- 生成的子组件必须是允许包含在LazyForEach父容器组件中的子组件。 13e41f4b71Sopenharmony_ci- 允许LazyForEach包含在if/else条件渲染语句中,也允许LazyForEach中出现if/else条件渲染语句。 14e41f4b71Sopenharmony_ci- 键值生成器必须针对每个数据生成唯一的值,如果键值相同,将导致键值相同的UI组件渲染出现问题。 15e41f4b71Sopenharmony_ci- LazyForEach必须使用DataChangeListener对象进行更新,对第一个参数dataSource重新赋值会异常;dataSource使用状态变量时,状态变量改变不会触发LazyForEach的UI刷新。 16e41f4b71Sopenharmony_ci- 为了高性能渲染,通过DataChangeListener对象的onDataChange方法来更新UI时,需要生成不同于原来的键值来触发组件刷新。 17e41f4b71Sopenharmony_ci- LazyForEach必须和[@Reusable](https://developer.huawei.com/consumer/cn/doc/best-practices-V5/bpta-component-reuse-V5#section5601835174020)装饰器一起使用才能触发节点复用。使用方法:将@Reusable装饰在LazyForEach列表的组件上,见[使用规则](https://developer.huawei.com/consumer/cn/doc/best-practices-V5/bpta-component-reuse-V5#section5923195311402)。 18e41f4b71Sopenharmony_ci 19e41f4b71Sopenharmony_ci## 键值生成规则 20e41f4b71Sopenharmony_ci 21e41f4b71Sopenharmony_ci在`LazyForEach`循环渲染过程中,系统会为每个item生成一个唯一且持久的键值,用于标识对应的组件。当这个键值变化时,ArkUI框架将视为该数组元素已被替换或修改,并会基于新的键值创建一个新的组件。 22e41f4b71Sopenharmony_ci 23e41f4b71Sopenharmony_ci`LazyForEach`提供了一个名为`keyGenerator`的参数,这是一个函数,开发者可以通过它自定义键值的生成规则。如果开发者没有定义`keyGenerator`函数,则ArkUI框架会使用默认的键值生成函数,即`(item: Object, index: number) => { return viewId + '-' + index.toString(); }`, viewId在编译器转换过程中生成,同一个LazyForEach组件内其viewId是一致的。 24e41f4b71Sopenharmony_ci 25e41f4b71Sopenharmony_ci## 组件创建规则 26e41f4b71Sopenharmony_ci 27e41f4b71Sopenharmony_ci在确定键值生成规则后,LazyForEach的第二个参数`itemGenerator`函数会根据键值生成规则为数据源的每个数组项创建组件。组件的创建包括两种情况:[LazyForEach首次渲染](#首次渲染)和[LazyForEach非首次渲染](#非首次渲染)。 28e41f4b71Sopenharmony_ci 29e41f4b71Sopenharmony_ci### 首次渲染 30e41f4b71Sopenharmony_ci 31e41f4b71Sopenharmony_ci#### 生成不同键值 32e41f4b71Sopenharmony_ci 33e41f4b71Sopenharmony_ci在LazyForEach首次渲染时,会根据上述键值生成规则为数据源的每个数组项生成唯一键值,并创建相应的组件。 34e41f4b71Sopenharmony_ci 35e41f4b71Sopenharmony_ci```ts 36e41f4b71Sopenharmony_ci// Basic implementation of IDataSource to handle data listener 37e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 38e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 39e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 40e41f4b71Sopenharmony_ci 41e41f4b71Sopenharmony_ci public totalCount(): number { 42e41f4b71Sopenharmony_ci return 0; 43e41f4b71Sopenharmony_ci } 44e41f4b71Sopenharmony_ci 45e41f4b71Sopenharmony_ci public getData(index: number): string { 46e41f4b71Sopenharmony_ci return this.originDataArray[index]; 47e41f4b71Sopenharmony_ci } 48e41f4b71Sopenharmony_ci 49e41f4b71Sopenharmony_ci // 该方法为框架侧调用,为LazyForEach组件向其数据源处添加listener监听 50e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 51e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 52e41f4b71Sopenharmony_ci console.info('add listener'); 53e41f4b71Sopenharmony_ci this.listeners.push(listener); 54e41f4b71Sopenharmony_ci } 55e41f4b71Sopenharmony_ci } 56e41f4b71Sopenharmony_ci 57e41f4b71Sopenharmony_ci // 该方法为框架侧调用,为对应的LazyForEach组件在数据源处去除listener监听 58e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 59e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 60e41f4b71Sopenharmony_ci if (pos >= 0) { 61e41f4b71Sopenharmony_ci console.info('remove listener'); 62e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 63e41f4b71Sopenharmony_ci } 64e41f4b71Sopenharmony_ci } 65e41f4b71Sopenharmony_ci 66e41f4b71Sopenharmony_ci // 通知LazyForEach组件需要重载所有子组件 67e41f4b71Sopenharmony_ci notifyDataReload(): void { 68e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 69e41f4b71Sopenharmony_ci listener.onDataReloaded(); 70e41f4b71Sopenharmony_ci }) 71e41f4b71Sopenharmony_ci } 72e41f4b71Sopenharmony_ci 73e41f4b71Sopenharmony_ci // 通知LazyForEach组件需要在index对应索引处添加子组件 74e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 75e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 76e41f4b71Sopenharmony_ci listener.onDataAdd(index); 77e41f4b71Sopenharmony_ci }) 78e41f4b71Sopenharmony_ci } 79e41f4b71Sopenharmony_ci 80e41f4b71Sopenharmony_ci // 通知LazyForEach组件在index对应索引处数据有变化,需要重建该子组件 81e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 82e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 83e41f4b71Sopenharmony_ci listener.onDataChange(index); 84e41f4b71Sopenharmony_ci }) 85e41f4b71Sopenharmony_ci } 86e41f4b71Sopenharmony_ci 87e41f4b71Sopenharmony_ci // 通知LazyForEach组件需要在index对应索引处删除该子组件 88e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 89e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 90e41f4b71Sopenharmony_ci listener.onDataDelete(index); 91e41f4b71Sopenharmony_ci }) 92e41f4b71Sopenharmony_ci } 93e41f4b71Sopenharmony_ci 94e41f4b71Sopenharmony_ci // 通知LazyForEach组件将from索引和to索引处的子组件进行交换 95e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 96e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 97e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 98e41f4b71Sopenharmony_ci }) 99e41f4b71Sopenharmony_ci } 100e41f4b71Sopenharmony_ci} 101e41f4b71Sopenharmony_ci 102e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 103e41f4b71Sopenharmony_ci private dataArray: string[] = []; 104e41f4b71Sopenharmony_ci 105e41f4b71Sopenharmony_ci public totalCount(): number { 106e41f4b71Sopenharmony_ci return this.dataArray.length; 107e41f4b71Sopenharmony_ci } 108e41f4b71Sopenharmony_ci 109e41f4b71Sopenharmony_ci public getData(index: number): string { 110e41f4b71Sopenharmony_ci return this.dataArray[index]; 111e41f4b71Sopenharmony_ci } 112e41f4b71Sopenharmony_ci 113e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 114e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 115e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 116e41f4b71Sopenharmony_ci } 117e41f4b71Sopenharmony_ci 118e41f4b71Sopenharmony_ci public pushData(data: string): void { 119e41f4b71Sopenharmony_ci this.dataArray.push(data); 120e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 121e41f4b71Sopenharmony_ci } 122e41f4b71Sopenharmony_ci} 123e41f4b71Sopenharmony_ci 124e41f4b71Sopenharmony_ci@Entry 125e41f4b71Sopenharmony_ci@Component 126e41f4b71Sopenharmony_cistruct MyComponent { 127e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 128e41f4b71Sopenharmony_ci 129e41f4b71Sopenharmony_ci aboutToAppear() { 130e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 131e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 132e41f4b71Sopenharmony_ci } 133e41f4b71Sopenharmony_ci } 134e41f4b71Sopenharmony_ci 135e41f4b71Sopenharmony_ci build() { 136e41f4b71Sopenharmony_ci List({ space: 3 }) { 137e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string) => { 138e41f4b71Sopenharmony_ci ListItem() { 139e41f4b71Sopenharmony_ci Row() { 140e41f4b71Sopenharmony_ci Text(item).fontSize(50) 141e41f4b71Sopenharmony_ci .onAppear(() => { 142e41f4b71Sopenharmony_ci console.info("appear:" + item) 143e41f4b71Sopenharmony_ci }) 144e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 145e41f4b71Sopenharmony_ci } 146e41f4b71Sopenharmony_ci }, (item: string) => item) 147e41f4b71Sopenharmony_ci }.cachedCount(5) 148e41f4b71Sopenharmony_ci } 149e41f4b71Sopenharmony_ci} 150e41f4b71Sopenharmony_ci``` 151e41f4b71Sopenharmony_ci 152e41f4b71Sopenharmony_ci在上述代码中,键值生成规则是`keyGenerator`函数的返回值`item`。在`LazyForEach`循环渲染时,其为数据源数组项依次生成键值`Hello 0`、`Hello 1` ... `Hello 20`,并创建对应的`ListItem`子组件渲染到界面上。 153e41f4b71Sopenharmony_ci 154e41f4b71Sopenharmony_ci运行效果如下图所示。 155e41f4b71Sopenharmony_ci 156e41f4b71Sopenharmony_ci**图1** LazyForEach正常首次渲染 157e41f4b71Sopenharmony_ci 158e41f4b71Sopenharmony_ci 159e41f4b71Sopenharmony_ci#### 键值相同时错误渲染 160e41f4b71Sopenharmony_ci 161e41f4b71Sopenharmony_ci当不同数据项生成的键值相同时,框架的行为是不可预测的。例如,在以下代码中,`LazyForEach`渲染的数据项键值均相同,在滑动过程中,`LazyForEach`会对划入划出当前页面的子组件进行预加载,而新建的子组件和销毁的原子组件具有相同的键值,框架可能存在取用缓存错误的情况,导致子组件渲染有问题。 162e41f4b71Sopenharmony_ci 163e41f4b71Sopenharmony_ci ```ts 164e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 165e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 166e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 167e41f4b71Sopenharmony_ci 168e41f4b71Sopenharmony_ci public totalCount(): number { 169e41f4b71Sopenharmony_ci return 0; 170e41f4b71Sopenharmony_ci } 171e41f4b71Sopenharmony_ci 172e41f4b71Sopenharmony_ci public getData(index: number): string { 173e41f4b71Sopenharmony_ci return this.originDataArray[index]; 174e41f4b71Sopenharmony_ci } 175e41f4b71Sopenharmony_ci 176e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 177e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 178e41f4b71Sopenharmony_ci console.info('add listener'); 179e41f4b71Sopenharmony_ci this.listeners.push(listener); 180e41f4b71Sopenharmony_ci } 181e41f4b71Sopenharmony_ci } 182e41f4b71Sopenharmony_ci 183e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 184e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 185e41f4b71Sopenharmony_ci if (pos >= 0) { 186e41f4b71Sopenharmony_ci console.info('remove listener'); 187e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 188e41f4b71Sopenharmony_ci } 189e41f4b71Sopenharmony_ci } 190e41f4b71Sopenharmony_ci 191e41f4b71Sopenharmony_ci notifyDataReload(): void { 192e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 193e41f4b71Sopenharmony_ci listener.onDataReloaded(); 194e41f4b71Sopenharmony_ci }) 195e41f4b71Sopenharmony_ci } 196e41f4b71Sopenharmony_ci 197e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 198e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 199e41f4b71Sopenharmony_ci listener.onDataAdd(index); 200e41f4b71Sopenharmony_ci }) 201e41f4b71Sopenharmony_ci } 202e41f4b71Sopenharmony_ci 203e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 204e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 205e41f4b71Sopenharmony_ci listener.onDataChange(index); 206e41f4b71Sopenharmony_ci }) 207e41f4b71Sopenharmony_ci } 208e41f4b71Sopenharmony_ci 209e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 210e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 211e41f4b71Sopenharmony_ci listener.onDataDelete(index); 212e41f4b71Sopenharmony_ci }) 213e41f4b71Sopenharmony_ci } 214e41f4b71Sopenharmony_ci 215e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 216e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 217e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 218e41f4b71Sopenharmony_ci }) 219e41f4b71Sopenharmony_ci } 220e41f4b71Sopenharmony_ci} 221e41f4b71Sopenharmony_ci 222e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 223e41f4b71Sopenharmony_ci private dataArray: string[] = []; 224e41f4b71Sopenharmony_ci 225e41f4b71Sopenharmony_ci public totalCount(): number { 226e41f4b71Sopenharmony_ci return this.dataArray.length; 227e41f4b71Sopenharmony_ci } 228e41f4b71Sopenharmony_ci 229e41f4b71Sopenharmony_ci public getData(index: number): string { 230e41f4b71Sopenharmony_ci return this.dataArray[index]; 231e41f4b71Sopenharmony_ci } 232e41f4b71Sopenharmony_ci 233e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 234e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 235e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 236e41f4b71Sopenharmony_ci } 237e41f4b71Sopenharmony_ci 238e41f4b71Sopenharmony_ci public pushData(data: string): void { 239e41f4b71Sopenharmony_ci this.dataArray.push(data); 240e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 241e41f4b71Sopenharmony_ci } 242e41f4b71Sopenharmony_ci} 243e41f4b71Sopenharmony_ci 244e41f4b71Sopenharmony_ci@Entry 245e41f4b71Sopenharmony_ci@Component 246e41f4b71Sopenharmony_cistruct MyComponent { 247e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 248e41f4b71Sopenharmony_ci 249e41f4b71Sopenharmony_ci aboutToAppear() { 250e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 251e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 252e41f4b71Sopenharmony_ci } 253e41f4b71Sopenharmony_ci } 254e41f4b71Sopenharmony_ci 255e41f4b71Sopenharmony_ci build() { 256e41f4b71Sopenharmony_ci List({ space: 3 }) { 257e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string) => { 258e41f4b71Sopenharmony_ci ListItem() { 259e41f4b71Sopenharmony_ci Row() { 260e41f4b71Sopenharmony_ci Text(item).fontSize(50) 261e41f4b71Sopenharmony_ci .onAppear(() => { 262e41f4b71Sopenharmony_ci console.info("appear:" + item) 263e41f4b71Sopenharmony_ci }) 264e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 265e41f4b71Sopenharmony_ci } 266e41f4b71Sopenharmony_ci }, (item: string) => 'same key') 267e41f4b71Sopenharmony_ci }.cachedCount(5) 268e41f4b71Sopenharmony_ci } 269e41f4b71Sopenharmony_ci} 270e41f4b71Sopenharmony_ci ``` 271e41f4b71Sopenharmony_ci 272e41f4b71Sopenharmony_ci运行效果如下图所示。 273e41f4b71Sopenharmony_ci 274e41f4b71Sopenharmony_ci**图2** LazyForEach存在相同键值 275e41f4b71Sopenharmony_ci 276e41f4b71Sopenharmony_ci 277e41f4b71Sopenharmony_ci### 非首次渲染 278e41f4b71Sopenharmony_ci 279e41f4b71Sopenharmony_ci当`LazyForEach`数据源发生变化,需要再次渲染时,开发者应根据数据源的变化情况调用`listener`对应的接口,通知`LazyForEach`做相应的更新,各使用场景如下。 280e41f4b71Sopenharmony_ci 281e41f4b71Sopenharmony_ci#### 添加数据 282e41f4b71Sopenharmony_ci 283e41f4b71Sopenharmony_ci```ts 284e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 285e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 286e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 287e41f4b71Sopenharmony_ci 288e41f4b71Sopenharmony_ci public totalCount(): number { 289e41f4b71Sopenharmony_ci return 0; 290e41f4b71Sopenharmony_ci } 291e41f4b71Sopenharmony_ci 292e41f4b71Sopenharmony_ci public getData(index: number): string { 293e41f4b71Sopenharmony_ci return this.originDataArray[index]; 294e41f4b71Sopenharmony_ci } 295e41f4b71Sopenharmony_ci 296e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 297e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 298e41f4b71Sopenharmony_ci console.info('add listener'); 299e41f4b71Sopenharmony_ci this.listeners.push(listener); 300e41f4b71Sopenharmony_ci } 301e41f4b71Sopenharmony_ci } 302e41f4b71Sopenharmony_ci 303e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 304e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 305e41f4b71Sopenharmony_ci if (pos >= 0) { 306e41f4b71Sopenharmony_ci console.info('remove listener'); 307e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 308e41f4b71Sopenharmony_ci } 309e41f4b71Sopenharmony_ci } 310e41f4b71Sopenharmony_ci 311e41f4b71Sopenharmony_ci notifyDataReload(): void { 312e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 313e41f4b71Sopenharmony_ci listener.onDataReloaded(); 314e41f4b71Sopenharmony_ci }) 315e41f4b71Sopenharmony_ci } 316e41f4b71Sopenharmony_ci 317e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 318e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 319e41f4b71Sopenharmony_ci listener.onDataAdd(index); 320e41f4b71Sopenharmony_ci // 写法2:listener.onDatasetChange([{type: DataOperationType.ADD, index: index}]); 321e41f4b71Sopenharmony_ci }) 322e41f4b71Sopenharmony_ci } 323e41f4b71Sopenharmony_ci 324e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 325e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 326e41f4b71Sopenharmony_ci listener.onDataChange(index); 327e41f4b71Sopenharmony_ci }) 328e41f4b71Sopenharmony_ci } 329e41f4b71Sopenharmony_ci 330e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 331e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 332e41f4b71Sopenharmony_ci listener.onDataDelete(index); 333e41f4b71Sopenharmony_ci }) 334e41f4b71Sopenharmony_ci } 335e41f4b71Sopenharmony_ci 336e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 337e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 338e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 339e41f4b71Sopenharmony_ci }) 340e41f4b71Sopenharmony_ci } 341e41f4b71Sopenharmony_ci} 342e41f4b71Sopenharmony_ci 343e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 344e41f4b71Sopenharmony_ci private dataArray: string[] = []; 345e41f4b71Sopenharmony_ci 346e41f4b71Sopenharmony_ci public totalCount(): number { 347e41f4b71Sopenharmony_ci return this.dataArray.length; 348e41f4b71Sopenharmony_ci } 349e41f4b71Sopenharmony_ci 350e41f4b71Sopenharmony_ci public getData(index: number): string { 351e41f4b71Sopenharmony_ci return this.dataArray[index]; 352e41f4b71Sopenharmony_ci } 353e41f4b71Sopenharmony_ci 354e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 355e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 356e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 357e41f4b71Sopenharmony_ci } 358e41f4b71Sopenharmony_ci 359e41f4b71Sopenharmony_ci public pushData(data: string): void { 360e41f4b71Sopenharmony_ci this.dataArray.push(data); 361e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 362e41f4b71Sopenharmony_ci } 363e41f4b71Sopenharmony_ci} 364e41f4b71Sopenharmony_ci 365e41f4b71Sopenharmony_ci@Entry 366e41f4b71Sopenharmony_ci@Component 367e41f4b71Sopenharmony_cistruct MyComponent { 368e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 369e41f4b71Sopenharmony_ci 370e41f4b71Sopenharmony_ci aboutToAppear() { 371e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 372e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 373e41f4b71Sopenharmony_ci } 374e41f4b71Sopenharmony_ci } 375e41f4b71Sopenharmony_ci 376e41f4b71Sopenharmony_ci build() { 377e41f4b71Sopenharmony_ci List({ space: 3 }) { 378e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string) => { 379e41f4b71Sopenharmony_ci ListItem() { 380e41f4b71Sopenharmony_ci Row() { 381e41f4b71Sopenharmony_ci Text(item).fontSize(50) 382e41f4b71Sopenharmony_ci .onAppear(() => { 383e41f4b71Sopenharmony_ci console.info("appear:" + item) 384e41f4b71Sopenharmony_ci }) 385e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 386e41f4b71Sopenharmony_ci } 387e41f4b71Sopenharmony_ci .onClick(() => { 388e41f4b71Sopenharmony_ci // 点击追加子组件 389e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${this.data.totalCount()}`); 390e41f4b71Sopenharmony_ci }) 391e41f4b71Sopenharmony_ci }, (item: string) => item) 392e41f4b71Sopenharmony_ci }.cachedCount(5) 393e41f4b71Sopenharmony_ci } 394e41f4b71Sopenharmony_ci} 395e41f4b71Sopenharmony_ci``` 396e41f4b71Sopenharmony_ci 397e41f4b71Sopenharmony_ci当我们点击`LazyForEach`的子组件时,首先调用数据源`data`的`pushData`方法,该方法会在数据源末尾添加数据并调用`notifyDataAdd`方法。在`notifyDataAdd`方法内会又调用`listener.onDataAdd`方法,该方法会通知`LazyForEach`在该处有数据添加,`LazyForEach`便会在该索引处新建子组件。 398e41f4b71Sopenharmony_ci 399e41f4b71Sopenharmony_ci运行效果如下图所示。 400e41f4b71Sopenharmony_ci 401e41f4b71Sopenharmony_ci**图3** LazyForEach添加数据 402e41f4b71Sopenharmony_ci 403e41f4b71Sopenharmony_ci 404e41f4b71Sopenharmony_ci#### 删除数据 405e41f4b71Sopenharmony_ci 406e41f4b71Sopenharmony_ci```ts 407e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 408e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 409e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 410e41f4b71Sopenharmony_ci 411e41f4b71Sopenharmony_ci public totalCount(): number { 412e41f4b71Sopenharmony_ci return 0; 413e41f4b71Sopenharmony_ci } 414e41f4b71Sopenharmony_ci 415e41f4b71Sopenharmony_ci public getData(index: number): string { 416e41f4b71Sopenharmony_ci return this.originDataArray[index]; 417e41f4b71Sopenharmony_ci } 418e41f4b71Sopenharmony_ci 419e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 420e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 421e41f4b71Sopenharmony_ci console.info('add listener'); 422e41f4b71Sopenharmony_ci this.listeners.push(listener); 423e41f4b71Sopenharmony_ci } 424e41f4b71Sopenharmony_ci } 425e41f4b71Sopenharmony_ci 426e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 427e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 428e41f4b71Sopenharmony_ci if (pos >= 0) { 429e41f4b71Sopenharmony_ci console.info('remove listener'); 430e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 431e41f4b71Sopenharmony_ci } 432e41f4b71Sopenharmony_ci } 433e41f4b71Sopenharmony_ci 434e41f4b71Sopenharmony_ci notifyDataReload(): void { 435e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 436e41f4b71Sopenharmony_ci listener.onDataReloaded(); 437e41f4b71Sopenharmony_ci }) 438e41f4b71Sopenharmony_ci } 439e41f4b71Sopenharmony_ci 440e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 441e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 442e41f4b71Sopenharmony_ci listener.onDataAdd(index); 443e41f4b71Sopenharmony_ci }) 444e41f4b71Sopenharmony_ci } 445e41f4b71Sopenharmony_ci 446e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 447e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 448e41f4b71Sopenharmony_ci listener.onDataChange(index); 449e41f4b71Sopenharmony_ci }) 450e41f4b71Sopenharmony_ci } 451e41f4b71Sopenharmony_ci 452e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 453e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 454e41f4b71Sopenharmony_ci listener.onDataDelete(index); 455e41f4b71Sopenharmony_ci // 写法2:listener.onDatasetChange([{type: DataOperationType.DELETE, index: index}]); 456e41f4b71Sopenharmony_ci }) 457e41f4b71Sopenharmony_ci } 458e41f4b71Sopenharmony_ci 459e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 460e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 461e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 462e41f4b71Sopenharmony_ci }) 463e41f4b71Sopenharmony_ci } 464e41f4b71Sopenharmony_ci} 465e41f4b71Sopenharmony_ci 466e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 467e41f4b71Sopenharmony_ci dataArray: string[] = []; 468e41f4b71Sopenharmony_ci 469e41f4b71Sopenharmony_ci public totalCount(): number { 470e41f4b71Sopenharmony_ci return this.dataArray.length; 471e41f4b71Sopenharmony_ci } 472e41f4b71Sopenharmony_ci 473e41f4b71Sopenharmony_ci public getData(index: number): string { 474e41f4b71Sopenharmony_ci return this.dataArray[index]; 475e41f4b71Sopenharmony_ci } 476e41f4b71Sopenharmony_ci 477e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 478e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 479e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 480e41f4b71Sopenharmony_ci } 481e41f4b71Sopenharmony_ci 482e41f4b71Sopenharmony_ci public pushData(data: string): void { 483e41f4b71Sopenharmony_ci this.dataArray.push(data); 484e41f4b71Sopenharmony_ci } 485e41f4b71Sopenharmony_ci 486e41f4b71Sopenharmony_ci public deleteData(index: number): void { 487e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 488e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 489e41f4b71Sopenharmony_ci } 490e41f4b71Sopenharmony_ci} 491e41f4b71Sopenharmony_ci 492e41f4b71Sopenharmony_ci@Entry 493e41f4b71Sopenharmony_ci@Component 494e41f4b71Sopenharmony_cistruct MyComponent { 495e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 496e41f4b71Sopenharmony_ci 497e41f4b71Sopenharmony_ci aboutToAppear() { 498e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 499e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 500e41f4b71Sopenharmony_ci } 501e41f4b71Sopenharmony_ci } 502e41f4b71Sopenharmony_ci 503e41f4b71Sopenharmony_ci build() { 504e41f4b71Sopenharmony_ci List({ space: 3 }) { 505e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 506e41f4b71Sopenharmony_ci ListItem() { 507e41f4b71Sopenharmony_ci Row() { 508e41f4b71Sopenharmony_ci Text(item).fontSize(50) 509e41f4b71Sopenharmony_ci .onAppear(() => { 510e41f4b71Sopenharmony_ci console.info("appear:" + item) 511e41f4b71Sopenharmony_ci }) 512e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 513e41f4b71Sopenharmony_ci } 514e41f4b71Sopenharmony_ci .onClick(() => { 515e41f4b71Sopenharmony_ci // 点击删除子组件 516e41f4b71Sopenharmony_ci this.data.deleteData(this.data.dataArray.indexOf(item)); 517e41f4b71Sopenharmony_ci }) 518e41f4b71Sopenharmony_ci }, (item: string) => item) 519e41f4b71Sopenharmony_ci }.cachedCount(5) 520e41f4b71Sopenharmony_ci } 521e41f4b71Sopenharmony_ci} 522e41f4b71Sopenharmony_ci``` 523e41f4b71Sopenharmony_ci 524e41f4b71Sopenharmony_ci当我们点击`LazyForEach`的子组件时,首先调用数据源`data`的`deleteData`方法,该方法会删除数据源对应索引处的数据并调用`notifyDataDelete`方法。在`notifyDataDelete`方法内会又调用`listener.onDataDelete`方法,该方法会通知`LazyForEach`在该处有数据删除,`LazyForEach`便会在该索引处删除对应子组件。 525e41f4b71Sopenharmony_ci 526e41f4b71Sopenharmony_ci运行效果如下图所示。 527e41f4b71Sopenharmony_ci 528e41f4b71Sopenharmony_ci**图4** LazyForEach删除数据 529e41f4b71Sopenharmony_ci 530e41f4b71Sopenharmony_ci 531e41f4b71Sopenharmony_ci#### 交换数据 532e41f4b71Sopenharmony_ci 533e41f4b71Sopenharmony_ci```ts 534e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 535e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 536e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 537e41f4b71Sopenharmony_ci 538e41f4b71Sopenharmony_ci public totalCount(): number { 539e41f4b71Sopenharmony_ci return 0; 540e41f4b71Sopenharmony_ci } 541e41f4b71Sopenharmony_ci 542e41f4b71Sopenharmony_ci public getData(index: number): string { 543e41f4b71Sopenharmony_ci return this.originDataArray[index]; 544e41f4b71Sopenharmony_ci } 545e41f4b71Sopenharmony_ci 546e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 547e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 548e41f4b71Sopenharmony_ci console.info('add listener'); 549e41f4b71Sopenharmony_ci this.listeners.push(listener); 550e41f4b71Sopenharmony_ci } 551e41f4b71Sopenharmony_ci } 552e41f4b71Sopenharmony_ci 553e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 554e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 555e41f4b71Sopenharmony_ci if (pos >= 0) { 556e41f4b71Sopenharmony_ci console.info('remove listener'); 557e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 558e41f4b71Sopenharmony_ci } 559e41f4b71Sopenharmony_ci } 560e41f4b71Sopenharmony_ci 561e41f4b71Sopenharmony_ci notifyDataReload(): void { 562e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 563e41f4b71Sopenharmony_ci listener.onDataReloaded(); 564e41f4b71Sopenharmony_ci }) 565e41f4b71Sopenharmony_ci } 566e41f4b71Sopenharmony_ci 567e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 568e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 569e41f4b71Sopenharmony_ci listener.onDataAdd(index); 570e41f4b71Sopenharmony_ci }) 571e41f4b71Sopenharmony_ci } 572e41f4b71Sopenharmony_ci 573e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 574e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 575e41f4b71Sopenharmony_ci listener.onDataChange(index); 576e41f4b71Sopenharmony_ci }) 577e41f4b71Sopenharmony_ci } 578e41f4b71Sopenharmony_ci 579e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 580e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 581e41f4b71Sopenharmony_ci listener.onDataDelete(index); 582e41f4b71Sopenharmony_ci }) 583e41f4b71Sopenharmony_ci } 584e41f4b71Sopenharmony_ci 585e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 586e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 587e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 588e41f4b71Sopenharmony_ci // 写法2:listener.onDatasetChange( 589e41f4b71Sopenharmony_ci // [{type: DataOperationType.EXCHANGE, index: {start: from, end: to}}]); 590e41f4b71Sopenharmony_ci }) 591e41f4b71Sopenharmony_ci } 592e41f4b71Sopenharmony_ci} 593e41f4b71Sopenharmony_ci 594e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 595e41f4b71Sopenharmony_ci dataArray: string[] = []; 596e41f4b71Sopenharmony_ci 597e41f4b71Sopenharmony_ci public totalCount(): number { 598e41f4b71Sopenharmony_ci return this.dataArray.length; 599e41f4b71Sopenharmony_ci } 600e41f4b71Sopenharmony_ci 601e41f4b71Sopenharmony_ci public getData(index: number): string { 602e41f4b71Sopenharmony_ci return this.dataArray[index]; 603e41f4b71Sopenharmony_ci } 604e41f4b71Sopenharmony_ci 605e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 606e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 607e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 608e41f4b71Sopenharmony_ci } 609e41f4b71Sopenharmony_ci 610e41f4b71Sopenharmony_ci public pushData(data: string): void { 611e41f4b71Sopenharmony_ci this.dataArray.push(data); 612e41f4b71Sopenharmony_ci } 613e41f4b71Sopenharmony_ci 614e41f4b71Sopenharmony_ci public deleteData(index: number): void { 615e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 616e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 617e41f4b71Sopenharmony_ci } 618e41f4b71Sopenharmony_ci 619e41f4b71Sopenharmony_ci public moveData(from: number, to: number): void { 620e41f4b71Sopenharmony_ci let temp: string = this.dataArray[from]; 621e41f4b71Sopenharmony_ci this.dataArray[from] = this.dataArray[to]; 622e41f4b71Sopenharmony_ci this.dataArray[to] = temp; 623e41f4b71Sopenharmony_ci this.notifyDataMove(from, to); 624e41f4b71Sopenharmony_ci } 625e41f4b71Sopenharmony_ci} 626e41f4b71Sopenharmony_ci 627e41f4b71Sopenharmony_ci@Entry 628e41f4b71Sopenharmony_ci@Component 629e41f4b71Sopenharmony_cistruct MyComponent { 630e41f4b71Sopenharmony_ci private moved: number[] = []; 631e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 632e41f4b71Sopenharmony_ci 633e41f4b71Sopenharmony_ci aboutToAppear() { 634e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 635e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 636e41f4b71Sopenharmony_ci } 637e41f4b71Sopenharmony_ci } 638e41f4b71Sopenharmony_ci 639e41f4b71Sopenharmony_ci build() { 640e41f4b71Sopenharmony_ci List({ space: 3 }) { 641e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 642e41f4b71Sopenharmony_ci ListItem() { 643e41f4b71Sopenharmony_ci Row() { 644e41f4b71Sopenharmony_ci Text(item).fontSize(50) 645e41f4b71Sopenharmony_ci .onAppear(() => { 646e41f4b71Sopenharmony_ci console.info("appear:" + item) 647e41f4b71Sopenharmony_ci }) 648e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 649e41f4b71Sopenharmony_ci } 650e41f4b71Sopenharmony_ci .onClick(() => { 651e41f4b71Sopenharmony_ci this.moved.push(this.data.dataArray.indexOf(item)); 652e41f4b71Sopenharmony_ci if (this.moved.length === 2) { 653e41f4b71Sopenharmony_ci // 点击交换子组件 654e41f4b71Sopenharmony_ci this.data.moveData(this.moved[0], this.moved[1]); 655e41f4b71Sopenharmony_ci this.moved = []; 656e41f4b71Sopenharmony_ci } 657e41f4b71Sopenharmony_ci }) 658e41f4b71Sopenharmony_ci }, (item: string) => item) 659e41f4b71Sopenharmony_ci }.cachedCount(5) 660e41f4b71Sopenharmony_ci } 661e41f4b71Sopenharmony_ci} 662e41f4b71Sopenharmony_ci``` 663e41f4b71Sopenharmony_ci 664e41f4b71Sopenharmony_ci当我们首次点击`LazyForEach`的子组件时,在moved成员变量内存入要移动的数据索引,再次点击`LazyForEach`另一个子组件时,我们将首次点击的子组件移到此处。调用数据源`data`的`moveData`方法,该方法会将数据源对应数据移动到预期的位置并调用`notifyDataMove`方法。在`notifyDataMove`方法内会又调用`listener.onDataMove`方法,该方法通知`LazyForEach`在该处有数据需要移动,`LazyForEach`便会将`from`和`to`索引处的子组件进行位置调换。 665e41f4b71Sopenharmony_ci 666e41f4b71Sopenharmony_ci运行效果如下图所示。 667e41f4b71Sopenharmony_ci 668e41f4b71Sopenharmony_ci**图5** LazyForEach交换数据 669e41f4b71Sopenharmony_ci 670e41f4b71Sopenharmony_ci 671e41f4b71Sopenharmony_ci#### 改变单个数据 672e41f4b71Sopenharmony_ci 673e41f4b71Sopenharmony_ci```ts 674e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 675e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 676e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 677e41f4b71Sopenharmony_ci 678e41f4b71Sopenharmony_ci public totalCount(): number { 679e41f4b71Sopenharmony_ci return 0; 680e41f4b71Sopenharmony_ci } 681e41f4b71Sopenharmony_ci 682e41f4b71Sopenharmony_ci public getData(index: number): string { 683e41f4b71Sopenharmony_ci return this.originDataArray[index]; 684e41f4b71Sopenharmony_ci } 685e41f4b71Sopenharmony_ci 686e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 687e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 688e41f4b71Sopenharmony_ci console.info('add listener'); 689e41f4b71Sopenharmony_ci this.listeners.push(listener); 690e41f4b71Sopenharmony_ci } 691e41f4b71Sopenharmony_ci } 692e41f4b71Sopenharmony_ci 693e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 694e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 695e41f4b71Sopenharmony_ci if (pos >= 0) { 696e41f4b71Sopenharmony_ci console.info('remove listener'); 697e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 698e41f4b71Sopenharmony_ci } 699e41f4b71Sopenharmony_ci } 700e41f4b71Sopenharmony_ci 701e41f4b71Sopenharmony_ci notifyDataReload(): void { 702e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 703e41f4b71Sopenharmony_ci listener.onDataReloaded(); 704e41f4b71Sopenharmony_ci }) 705e41f4b71Sopenharmony_ci } 706e41f4b71Sopenharmony_ci 707e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 708e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 709e41f4b71Sopenharmony_ci listener.onDataAdd(index); 710e41f4b71Sopenharmony_ci }) 711e41f4b71Sopenharmony_ci } 712e41f4b71Sopenharmony_ci 713e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 714e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 715e41f4b71Sopenharmony_ci listener.onDataChange(index); 716e41f4b71Sopenharmony_ci // 写法2:listener.onDatasetChange([{type: DataOperationType.CHANGE, index: index}]); 717e41f4b71Sopenharmony_ci }) 718e41f4b71Sopenharmony_ci } 719e41f4b71Sopenharmony_ci 720e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 721e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 722e41f4b71Sopenharmony_ci listener.onDataDelete(index); 723e41f4b71Sopenharmony_ci }) 724e41f4b71Sopenharmony_ci } 725e41f4b71Sopenharmony_ci 726e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 727e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 728e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 729e41f4b71Sopenharmony_ci }) 730e41f4b71Sopenharmony_ci } 731e41f4b71Sopenharmony_ci} 732e41f4b71Sopenharmony_ci 733e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 734e41f4b71Sopenharmony_ci private dataArray: string[] = []; 735e41f4b71Sopenharmony_ci 736e41f4b71Sopenharmony_ci public totalCount(): number { 737e41f4b71Sopenharmony_ci return this.dataArray.length; 738e41f4b71Sopenharmony_ci } 739e41f4b71Sopenharmony_ci 740e41f4b71Sopenharmony_ci public getData(index: number): string { 741e41f4b71Sopenharmony_ci return this.dataArray[index]; 742e41f4b71Sopenharmony_ci } 743e41f4b71Sopenharmony_ci 744e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 745e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 746e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 747e41f4b71Sopenharmony_ci } 748e41f4b71Sopenharmony_ci 749e41f4b71Sopenharmony_ci public pushData(data: string): void { 750e41f4b71Sopenharmony_ci this.dataArray.push(data); 751e41f4b71Sopenharmony_ci } 752e41f4b71Sopenharmony_ci 753e41f4b71Sopenharmony_ci public deleteData(index: number): void { 754e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 755e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 756e41f4b71Sopenharmony_ci } 757e41f4b71Sopenharmony_ci 758e41f4b71Sopenharmony_ci public changeData(index: number, data: string): void { 759e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1, data); 760e41f4b71Sopenharmony_ci this.notifyDataChange(index); 761e41f4b71Sopenharmony_ci } 762e41f4b71Sopenharmony_ci} 763e41f4b71Sopenharmony_ci 764e41f4b71Sopenharmony_ci@Entry 765e41f4b71Sopenharmony_ci@Component 766e41f4b71Sopenharmony_cistruct MyComponent { 767e41f4b71Sopenharmony_ci private moved: number[] = []; 768e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 769e41f4b71Sopenharmony_ci 770e41f4b71Sopenharmony_ci aboutToAppear() { 771e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 772e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 773e41f4b71Sopenharmony_ci } 774e41f4b71Sopenharmony_ci } 775e41f4b71Sopenharmony_ci 776e41f4b71Sopenharmony_ci 777e41f4b71Sopenharmony_ci build() { 778e41f4b71Sopenharmony_ci List({ space: 3 }) { 779e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 780e41f4b71Sopenharmony_ci ListItem() { 781e41f4b71Sopenharmony_ci Row() { 782e41f4b71Sopenharmony_ci Text(item).fontSize(50) 783e41f4b71Sopenharmony_ci .onAppear(() => { 784e41f4b71Sopenharmony_ci console.info("appear:" + item) 785e41f4b71Sopenharmony_ci }) 786e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 787e41f4b71Sopenharmony_ci } 788e41f4b71Sopenharmony_ci .onClick(() => { 789e41f4b71Sopenharmony_ci this.data.changeData(index, item + '00'); 790e41f4b71Sopenharmony_ci }) 791e41f4b71Sopenharmony_ci }, (item: string) => item) 792e41f4b71Sopenharmony_ci }.cachedCount(5) 793e41f4b71Sopenharmony_ci } 794e41f4b71Sopenharmony_ci} 795e41f4b71Sopenharmony_ci``` 796e41f4b71Sopenharmony_ci 797e41f4b71Sopenharmony_ci当我们点击`LazyForEach`的子组件时,首先改变当前数据,然后调用数据源`data`的`changeData`方法,在该方法内会调用`notifyDataChange`方法。在`notifyDataChange`方法内会又调用`listener.onDataChange`方法,该方法通知`LazyForEach`组件该处有数据发生变化,`LazyForEach`便会在对应索引处重建子组件。 798e41f4b71Sopenharmony_ci 799e41f4b71Sopenharmony_ci运行效果如下图所示。 800e41f4b71Sopenharmony_ci 801e41f4b71Sopenharmony_ci**图6** LazyForEach改变单个数据 802e41f4b71Sopenharmony_ci 803e41f4b71Sopenharmony_ci 804e41f4b71Sopenharmony_ci#### 改变多个数据 805e41f4b71Sopenharmony_ci 806e41f4b71Sopenharmony_ci```ts 807e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 808e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 809e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 810e41f4b71Sopenharmony_ci 811e41f4b71Sopenharmony_ci public totalCount(): number { 812e41f4b71Sopenharmony_ci return 0; 813e41f4b71Sopenharmony_ci } 814e41f4b71Sopenharmony_ci 815e41f4b71Sopenharmony_ci public getData(index: number): string { 816e41f4b71Sopenharmony_ci return this.originDataArray[index]; 817e41f4b71Sopenharmony_ci } 818e41f4b71Sopenharmony_ci 819e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 820e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 821e41f4b71Sopenharmony_ci console.info('add listener'); 822e41f4b71Sopenharmony_ci this.listeners.push(listener); 823e41f4b71Sopenharmony_ci } 824e41f4b71Sopenharmony_ci } 825e41f4b71Sopenharmony_ci 826e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 827e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 828e41f4b71Sopenharmony_ci if (pos >= 0) { 829e41f4b71Sopenharmony_ci console.info('remove listener'); 830e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 831e41f4b71Sopenharmony_ci } 832e41f4b71Sopenharmony_ci } 833e41f4b71Sopenharmony_ci 834e41f4b71Sopenharmony_ci notifyDataReload(): void { 835e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 836e41f4b71Sopenharmony_ci listener.onDataReloaded(); 837e41f4b71Sopenharmony_ci // 写法2:listener.onDatasetChange([{type: DataOperationType.RELOAD}]); 838e41f4b71Sopenharmony_ci }) 839e41f4b71Sopenharmony_ci } 840e41f4b71Sopenharmony_ci 841e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 842e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 843e41f4b71Sopenharmony_ci listener.onDataAdd(index); 844e41f4b71Sopenharmony_ci }) 845e41f4b71Sopenharmony_ci } 846e41f4b71Sopenharmony_ci 847e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 848e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 849e41f4b71Sopenharmony_ci listener.onDataChange(index); 850e41f4b71Sopenharmony_ci }) 851e41f4b71Sopenharmony_ci } 852e41f4b71Sopenharmony_ci 853e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 854e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 855e41f4b71Sopenharmony_ci listener.onDataDelete(index); 856e41f4b71Sopenharmony_ci }) 857e41f4b71Sopenharmony_ci } 858e41f4b71Sopenharmony_ci 859e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 860e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 861e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 862e41f4b71Sopenharmony_ci }) 863e41f4b71Sopenharmony_ci } 864e41f4b71Sopenharmony_ci} 865e41f4b71Sopenharmony_ci 866e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 867e41f4b71Sopenharmony_ci private dataArray: string[] = []; 868e41f4b71Sopenharmony_ci 869e41f4b71Sopenharmony_ci public totalCount(): number { 870e41f4b71Sopenharmony_ci return this.dataArray.length; 871e41f4b71Sopenharmony_ci } 872e41f4b71Sopenharmony_ci 873e41f4b71Sopenharmony_ci public getData(index: number): string { 874e41f4b71Sopenharmony_ci return this.dataArray[index]; 875e41f4b71Sopenharmony_ci } 876e41f4b71Sopenharmony_ci 877e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 878e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 879e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 880e41f4b71Sopenharmony_ci } 881e41f4b71Sopenharmony_ci 882e41f4b71Sopenharmony_ci public pushData(data: string): void { 883e41f4b71Sopenharmony_ci this.dataArray.push(data); 884e41f4b71Sopenharmony_ci } 885e41f4b71Sopenharmony_ci 886e41f4b71Sopenharmony_ci public deleteData(index: number): void { 887e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 888e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 889e41f4b71Sopenharmony_ci } 890e41f4b71Sopenharmony_ci 891e41f4b71Sopenharmony_ci public changeData(index: number): void { 892e41f4b71Sopenharmony_ci this.notifyDataChange(index); 893e41f4b71Sopenharmony_ci } 894e41f4b71Sopenharmony_ci 895e41f4b71Sopenharmony_ci public reloadData(): void { 896e41f4b71Sopenharmony_ci this.notifyDataReload(); 897e41f4b71Sopenharmony_ci } 898e41f4b71Sopenharmony_ci 899e41f4b71Sopenharmony_ci public modifyAllData(): void { 900e41f4b71Sopenharmony_ci this.dataArray = this.dataArray.map((item: string) => { 901e41f4b71Sopenharmony_ci return item + '0'; 902e41f4b71Sopenharmony_ci }) 903e41f4b71Sopenharmony_ci } 904e41f4b71Sopenharmony_ci} 905e41f4b71Sopenharmony_ci 906e41f4b71Sopenharmony_ci@Entry 907e41f4b71Sopenharmony_ci@Component 908e41f4b71Sopenharmony_cistruct MyComponent { 909e41f4b71Sopenharmony_ci private moved: number[] = []; 910e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 911e41f4b71Sopenharmony_ci 912e41f4b71Sopenharmony_ci aboutToAppear() { 913e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 914e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 915e41f4b71Sopenharmony_ci } 916e41f4b71Sopenharmony_ci } 917e41f4b71Sopenharmony_ci 918e41f4b71Sopenharmony_ci build() { 919e41f4b71Sopenharmony_ci List({ space: 3 }) { 920e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 921e41f4b71Sopenharmony_ci ListItem() { 922e41f4b71Sopenharmony_ci Row() { 923e41f4b71Sopenharmony_ci Text(item).fontSize(50) 924e41f4b71Sopenharmony_ci .onAppear(() => { 925e41f4b71Sopenharmony_ci console.info("appear:" + item) 926e41f4b71Sopenharmony_ci }) 927e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 928e41f4b71Sopenharmony_ci } 929e41f4b71Sopenharmony_ci .onClick(() => { 930e41f4b71Sopenharmony_ci this.data.modifyAllData(); 931e41f4b71Sopenharmony_ci this.data.reloadData(); 932e41f4b71Sopenharmony_ci }) 933e41f4b71Sopenharmony_ci }, (item: string) => item) 934e41f4b71Sopenharmony_ci }.cachedCount(5) 935e41f4b71Sopenharmony_ci } 936e41f4b71Sopenharmony_ci} 937e41f4b71Sopenharmony_ci``` 938e41f4b71Sopenharmony_ci 939e41f4b71Sopenharmony_ci当我们点击`LazyForEach`的子组件时,首先调用`data`的`modifyAllData`方法改变了数据源中的所有数据,然后调用数据源的`reloadData`方法,在该方法内会调用`notifyDataReload`方法。在`notifyDataReload`方法内会又调用`listener.onDataReloaded`方法,通知`LazyForEach`需要重建所有子节点。`LazyForEach`会将原所有数据项和新所有数据项一一做键值比对,若有相同键值则使用缓存,若键值不同则重新构建。 940e41f4b71Sopenharmony_ci 941e41f4b71Sopenharmony_ci运行效果如下图所示。 942e41f4b71Sopenharmony_ci 943e41f4b71Sopenharmony_ci**图7** LazyForEach改变多个数据 944e41f4b71Sopenharmony_ci 945e41f4b71Sopenharmony_ci 946e41f4b71Sopenharmony_ci#### 精准批量修改数据 947e41f4b71Sopenharmony_ci 948e41f4b71Sopenharmony_ci```ts 949e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 950e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 951e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 952e41f4b71Sopenharmony_ci 953e41f4b71Sopenharmony_ci public totalCount(): number { 954e41f4b71Sopenharmony_ci return 0; 955e41f4b71Sopenharmony_ci } 956e41f4b71Sopenharmony_ci 957e41f4b71Sopenharmony_ci public getData(index: number): string { 958e41f4b71Sopenharmony_ci return this.originDataArray[index]; 959e41f4b71Sopenharmony_ci } 960e41f4b71Sopenharmony_ci 961e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 962e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 963e41f4b71Sopenharmony_ci console.info('add listener'); 964e41f4b71Sopenharmony_ci this.listeners.push(listener); 965e41f4b71Sopenharmony_ci } 966e41f4b71Sopenharmony_ci } 967e41f4b71Sopenharmony_ci 968e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 969e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 970e41f4b71Sopenharmony_ci if (pos >= 0) { 971e41f4b71Sopenharmony_ci console.info('remove listener'); 972e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 973e41f4b71Sopenharmony_ci } 974e41f4b71Sopenharmony_ci } 975e41f4b71Sopenharmony_ci 976e41f4b71Sopenharmony_ci notifyDatasetChange(operations: DataOperation[]): void { 977e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 978e41f4b71Sopenharmony_ci listener.onDatasetChange(operations); 979e41f4b71Sopenharmony_ci }) 980e41f4b71Sopenharmony_ci } 981e41f4b71Sopenharmony_ci} 982e41f4b71Sopenharmony_ci 983e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 984e41f4b71Sopenharmony_ci private dataArray: string[] = []; 985e41f4b71Sopenharmony_ci 986e41f4b71Sopenharmony_ci public totalCount(): number { 987e41f4b71Sopenharmony_ci return this.dataArray.length; 988e41f4b71Sopenharmony_ci } 989e41f4b71Sopenharmony_ci 990e41f4b71Sopenharmony_ci public getData(index: number): string { 991e41f4b71Sopenharmony_ci return this.dataArray[index]; 992e41f4b71Sopenharmony_ci } 993e41f4b71Sopenharmony_ci 994e41f4b71Sopenharmony_ci public operateData(): void { 995e41f4b71Sopenharmony_ci console.info(JSON.stringify(this.dataArray)); 996e41f4b71Sopenharmony_ci this.dataArray.splice(4, 0, this.dataArray[1]); 997e41f4b71Sopenharmony_ci this.dataArray.splice(1, 1); 998e41f4b71Sopenharmony_ci let temp = this.dataArray[4]; 999e41f4b71Sopenharmony_ci this.dataArray[4] = this.dataArray[6]; 1000e41f4b71Sopenharmony_ci this.dataArray[6] = temp 1001e41f4b71Sopenharmony_ci this.dataArray.splice(8, 0, 'Hello 1', 'Hello 2'); 1002e41f4b71Sopenharmony_ci this.dataArray.splice(12, 2); 1003e41f4b71Sopenharmony_ci console.info(JSON.stringify(this.dataArray)); 1004e41f4b71Sopenharmony_ci this.notifyDatasetChange([ 1005e41f4b71Sopenharmony_ci { type: DataOperationType.MOVE, index: { from: 1, to: 3 } }, 1006e41f4b71Sopenharmony_ci { type: DataOperationType.EXCHANGE, index: { start: 4, end: 6 } }, 1007e41f4b71Sopenharmony_ci { type: DataOperationType.ADD, index: 8, count: 2 }, 1008e41f4b71Sopenharmony_ci { type: DataOperationType.DELETE, index: 10, count: 2 }]); 1009e41f4b71Sopenharmony_ci } 1010e41f4b71Sopenharmony_ci 1011e41f4b71Sopenharmony_ci public init(): void { 1012e41f4b71Sopenharmony_ci this.dataArray.splice(0, 0, 'Hello a', 'Hello b', 'Hello c', 'Hello d', 'Hello e', 'Hello f', 'Hello g', 'Hello h', 1013e41f4b71Sopenharmony_ci 'Hello i', 'Hello j', 'Hello k', 'Hello l', 'Hello m', 'Hello n', 'Hello o', 'Hello p', 'Hello q', 'Hello r'); 1014e41f4b71Sopenharmony_ci } 1015e41f4b71Sopenharmony_ci} 1016e41f4b71Sopenharmony_ci 1017e41f4b71Sopenharmony_ci@Entry 1018e41f4b71Sopenharmony_ci@Component 1019e41f4b71Sopenharmony_cistruct MyComponent { 1020e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 1021e41f4b71Sopenharmony_ci 1022e41f4b71Sopenharmony_ci aboutToAppear() { 1023e41f4b71Sopenharmony_ci this.data.init() 1024e41f4b71Sopenharmony_ci } 1025e41f4b71Sopenharmony_ci 1026e41f4b71Sopenharmony_ci build() { 1027e41f4b71Sopenharmony_ci Column() { 1028e41f4b71Sopenharmony_ci Text('第二项数据移动到第四项处,第五项数据和第七项数据交换,第九项开始添加数据 "Hello 1" "Hello 2", 第十一项开始删除两个数据') 1029e41f4b71Sopenharmony_ci .fontSize(10) 1030e41f4b71Sopenharmony_ci .backgroundColor(Color.Blue) 1031e41f4b71Sopenharmony_ci .fontColor(Color.White) 1032e41f4b71Sopenharmony_ci .borderRadius(50) 1033e41f4b71Sopenharmony_ci .padding(5) 1034e41f4b71Sopenharmony_ci .onClick(() => { 1035e41f4b71Sopenharmony_ci this.data.operateData(); 1036e41f4b71Sopenharmony_ci }) 1037e41f4b71Sopenharmony_ci List({ space: 3 }) { 1038e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 1039e41f4b71Sopenharmony_ci ListItem() { 1040e41f4b71Sopenharmony_ci Row() { 1041e41f4b71Sopenharmony_ci Text(item).fontSize(35) 1042e41f4b71Sopenharmony_ci .onAppear(() => { 1043e41f4b71Sopenharmony_ci console.info("appear:" + item) 1044e41f4b71Sopenharmony_ci }) 1045e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 1046e41f4b71Sopenharmony_ci } 1047e41f4b71Sopenharmony_ci 1048e41f4b71Sopenharmony_ci }, (item: string) => item + new Date().getTime()) 1049e41f4b71Sopenharmony_ci }.cachedCount(5) 1050e41f4b71Sopenharmony_ci } 1051e41f4b71Sopenharmony_ci } 1052e41f4b71Sopenharmony_ci} 1053e41f4b71Sopenharmony_ci``` 1054e41f4b71Sopenharmony_ci 1055e41f4b71Sopenharmony_cionDatasetChange接口由开发者一次性通知LazyForEach应该做哪些操作。上述例子展示了LazyForEach同时进行数据添加、删除、移动、交换的操作。 1056e41f4b71Sopenharmony_ci 1057e41f4b71Sopenharmony_ci**图8** LazyForEach改变多个数据 1058e41f4b71Sopenharmony_ci 1059e41f4b71Sopenharmony_ci 1060e41f4b71Sopenharmony_ci 1061e41f4b71Sopenharmony_ci第二个例子,直接给数组赋值,不涉及 splice 操作。operations直接从比较原数组和新数组得到。 1062e41f4b71Sopenharmony_ci```ts 1063e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 1064e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1065e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 1066e41f4b71Sopenharmony_ci 1067e41f4b71Sopenharmony_ci public totalCount(): number { 1068e41f4b71Sopenharmony_ci return 0; 1069e41f4b71Sopenharmony_ci } 1070e41f4b71Sopenharmony_ci 1071e41f4b71Sopenharmony_ci public getData(index: number): string { 1072e41f4b71Sopenharmony_ci return this.originDataArray[index]; 1073e41f4b71Sopenharmony_ci } 1074e41f4b71Sopenharmony_ci 1075e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 1076e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 1077e41f4b71Sopenharmony_ci console.info('add listener'); 1078e41f4b71Sopenharmony_ci this.listeners.push(listener); 1079e41f4b71Sopenharmony_ci } 1080e41f4b71Sopenharmony_ci } 1081e41f4b71Sopenharmony_ci 1082e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 1083e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 1084e41f4b71Sopenharmony_ci if (pos >= 0) { 1085e41f4b71Sopenharmony_ci console.info('remove listener'); 1086e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 1087e41f4b71Sopenharmony_ci } 1088e41f4b71Sopenharmony_ci } 1089e41f4b71Sopenharmony_ci 1090e41f4b71Sopenharmony_ci notifyDatasetChange(operations: DataOperation[]): void { 1091e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1092e41f4b71Sopenharmony_ci listener.onDatasetChange(operations); 1093e41f4b71Sopenharmony_ci }) 1094e41f4b71Sopenharmony_ci } 1095e41f4b71Sopenharmony_ci} 1096e41f4b71Sopenharmony_ci 1097e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 1098e41f4b71Sopenharmony_ci private dataArray: string[] = []; 1099e41f4b71Sopenharmony_ci 1100e41f4b71Sopenharmony_ci public totalCount(): number { 1101e41f4b71Sopenharmony_ci return this.dataArray.length; 1102e41f4b71Sopenharmony_ci } 1103e41f4b71Sopenharmony_ci 1104e41f4b71Sopenharmony_ci public getData(index: number): string { 1105e41f4b71Sopenharmony_ci return this.dataArray[index]; 1106e41f4b71Sopenharmony_ci } 1107e41f4b71Sopenharmony_ci 1108e41f4b71Sopenharmony_ci public operateData(): void { 1109e41f4b71Sopenharmony_ci this.dataArray = 1110e41f4b71Sopenharmony_ci ['Hello x', 'Hello 1', 'Hello 2', 'Hello b', 'Hello c', 'Hello e', 'Hello d', 'Hello f', 'Hello g', 'Hello h'] 1111e41f4b71Sopenharmony_ci this.notifyDatasetChange([ 1112e41f4b71Sopenharmony_ci { type: DataOperationType.CHANGE, index: 0 }, 1113e41f4b71Sopenharmony_ci { type: DataOperationType.ADD, index: 1, count: 2 }, 1114e41f4b71Sopenharmony_ci { type: DataOperationType.EXCHANGE, index: { start: 3, end: 4 } }, 1115e41f4b71Sopenharmony_ci ]); 1116e41f4b71Sopenharmony_ci } 1117e41f4b71Sopenharmony_ci 1118e41f4b71Sopenharmony_ci public init(): void { 1119e41f4b71Sopenharmony_ci this.dataArray = ['Hello a', 'Hello b', 'Hello c', 'Hello d', 'Hello e', 'Hello f', 'Hello g', 'Hello h']; 1120e41f4b71Sopenharmony_ci } 1121e41f4b71Sopenharmony_ci} 1122e41f4b71Sopenharmony_ci 1123e41f4b71Sopenharmony_ci@Entry 1124e41f4b71Sopenharmony_ci@Component 1125e41f4b71Sopenharmony_cistruct MyComponent { 1126e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 1127e41f4b71Sopenharmony_ci 1128e41f4b71Sopenharmony_ci aboutToAppear() { 1129e41f4b71Sopenharmony_ci this.data.init() 1130e41f4b71Sopenharmony_ci } 1131e41f4b71Sopenharmony_ci 1132e41f4b71Sopenharmony_ci build() { 1133e41f4b71Sopenharmony_ci Column() { 1134e41f4b71Sopenharmony_ci Text('Multi-Data Change') 1135e41f4b71Sopenharmony_ci .fontSize(10) 1136e41f4b71Sopenharmony_ci .backgroundColor(Color.Blue) 1137e41f4b71Sopenharmony_ci .fontColor(Color.White) 1138e41f4b71Sopenharmony_ci .borderRadius(50) 1139e41f4b71Sopenharmony_ci .padding(5) 1140e41f4b71Sopenharmony_ci .onClick(() => { 1141e41f4b71Sopenharmony_ci this.data.operateData(); 1142e41f4b71Sopenharmony_ci }) 1143e41f4b71Sopenharmony_ci List({ space: 3 }) { 1144e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 1145e41f4b71Sopenharmony_ci ListItem() { 1146e41f4b71Sopenharmony_ci Row() { 1147e41f4b71Sopenharmony_ci Text(item).fontSize(35) 1148e41f4b71Sopenharmony_ci .onAppear(() => { 1149e41f4b71Sopenharmony_ci console.info("appear:" + item) 1150e41f4b71Sopenharmony_ci }) 1151e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 1152e41f4b71Sopenharmony_ci } 1153e41f4b71Sopenharmony_ci 1154e41f4b71Sopenharmony_ci }, (item: string) => item + new Date().getTime()) 1155e41f4b71Sopenharmony_ci }.cachedCount(5) 1156e41f4b71Sopenharmony_ci } 1157e41f4b71Sopenharmony_ci } 1158e41f4b71Sopenharmony_ci} 1159e41f4b71Sopenharmony_ci``` 1160e41f4b71Sopenharmony_ci**图9** LazyForEach改变多个数据 1161e41f4b71Sopenharmony_ci 1162e41f4b71Sopenharmony_ci 1163e41f4b71Sopenharmony_ci 1164e41f4b71Sopenharmony_ci使用该接口时有如下注意事项。 1165e41f4b71Sopenharmony_ci 1166e41f4b71Sopenharmony_ci1. onDatasetChange与其它操作数据的接口不能混用。 1167e41f4b71Sopenharmony_ci2. 传入onDatasetChange的operations,其中每一项operation的index均从修改前的原数组内寻找。因此,operations中的index跟操作Datasource中的index不总是一一对应的,而且不能是负数。 1168e41f4b71Sopenharmony_ci第一个例子清楚地显示了这一点: 1169e41f4b71Sopenharmony_ci```ts 1170e41f4b71Sopenharmony_ci// 修改之前的数组 1171e41f4b71Sopenharmony_ci["Hello a","Hello b","Hello c","Hello d","Hello e","Hello f","Hello g","Hello h","Hello i","Hello j","Hello k","Hello l","Hello m","Hello n","Hello o","Hello p","Hello q","Hello r"] 1172e41f4b71Sopenharmony_ci// 修改之后的数组 1173e41f4b71Sopenharmony_ci["Hello a","Hello c","Hello d","Hello b","Hello g","Hello f","Hello e","Hello h","Hello 1","Hello 2","Hello i","Hello j","Hello m","Hello n","Hello o","Hello p","Hello q","Hello r"] 1174e41f4b71Sopenharmony_ci``` 1175e41f4b71Sopenharmony_ci"Hello b" 从第2项变成第4项,因此第一个 operation 为 `{ type: DataOperationType.MOVE, index: { from: 1, to: 3 } }` 1176e41f4b71Sopenharmony_ci"Hello e" 跟 "Hello g" 对调了,而 "Hello e" 在修改前的原数组中的 index=4,"Hello g" 在修改前的原数组中的 index=6, 因此第二个 operation 为 `{ type: DataOperationType.EXCHANGE, index: { start: 4, end: 6 } }` 1177e41f4b71Sopenharmony_ci"Hello 1","Hello 2" 在 "Hello h" 之后插入,而 "Hello h" 在修改前的原数组中的 index=7,因此第三个 operation 为 `{ type: DataOperationType.ADD, index: 8, count: 2 }` 1178e41f4b71Sopenharmony_ci"Hello k","Hello l" 被删除了,而 "Hello k" 在原数组中的 index=10,因此第四个 operation 为 `{ type: DataOperationType.DELETE, index: 10, count: 2 }` 1179e41f4b71Sopenharmony_ci 1180e41f4b71Sopenharmony_ci3. 调用一次onDatasetChange,一个index对应的数据只能被操作一次,若被操作多次,LazyForEach仅使第一个操作生效。 1181e41f4b71Sopenharmony_ci4. 部分操作可以由开发者传入键值,LazyForEach不会再去重复调用keygenerator获取键值,需要开发者保证传入的键值的正确性。 1182e41f4b71Sopenharmony_ci5. 若本次操作集合中有RELOAD操作,则其余操作全不生效。 1183e41f4b71Sopenharmony_ci 1184e41f4b71Sopenharmony_ci 1185e41f4b71Sopenharmony_ci 1186e41f4b71Sopenharmony_ci- ### 改变数据子属性 1187e41f4b71Sopenharmony_ci 1188e41f4b71Sopenharmony_ci若仅靠`LazyForEach`的刷新机制,当`item`变化时若想更新子组件,需要将原来的子组件全部销毁再重新构建,在子组件结构较为复杂的情况下,靠改变键值去刷新渲染性能较低。因此框架提供了`@Observed`与@`ObjectLink`机制进行深度观测,可以做到仅刷新使用了该属性的组件,提高渲染性能。开发者可根据其自身业务特点选择使用哪种刷新方式。 1189e41f4b71Sopenharmony_ci 1190e41f4b71Sopenharmony_ci```ts 1191e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 1192e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1193e41f4b71Sopenharmony_ci private originDataArray: StringData[] = []; 1194e41f4b71Sopenharmony_ci 1195e41f4b71Sopenharmony_ci public totalCount(): number { 1196e41f4b71Sopenharmony_ci return 0; 1197e41f4b71Sopenharmony_ci } 1198e41f4b71Sopenharmony_ci 1199e41f4b71Sopenharmony_ci public getData(index: number): StringData { 1200e41f4b71Sopenharmony_ci return this.originDataArray[index]; 1201e41f4b71Sopenharmony_ci } 1202e41f4b71Sopenharmony_ci 1203e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 1204e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 1205e41f4b71Sopenharmony_ci console.info('add listener'); 1206e41f4b71Sopenharmony_ci this.listeners.push(listener); 1207e41f4b71Sopenharmony_ci } 1208e41f4b71Sopenharmony_ci } 1209e41f4b71Sopenharmony_ci 1210e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 1211e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 1212e41f4b71Sopenharmony_ci if (pos >= 0) { 1213e41f4b71Sopenharmony_ci console.info('remove listener'); 1214e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 1215e41f4b71Sopenharmony_ci } 1216e41f4b71Sopenharmony_ci } 1217e41f4b71Sopenharmony_ci 1218e41f4b71Sopenharmony_ci notifyDataReload(): void { 1219e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1220e41f4b71Sopenharmony_ci listener.onDataReloaded(); 1221e41f4b71Sopenharmony_ci }) 1222e41f4b71Sopenharmony_ci } 1223e41f4b71Sopenharmony_ci 1224e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 1225e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1226e41f4b71Sopenharmony_ci listener.onDataAdd(index); 1227e41f4b71Sopenharmony_ci }) 1228e41f4b71Sopenharmony_ci } 1229e41f4b71Sopenharmony_ci 1230e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 1231e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1232e41f4b71Sopenharmony_ci listener.onDataChange(index); 1233e41f4b71Sopenharmony_ci }) 1234e41f4b71Sopenharmony_ci } 1235e41f4b71Sopenharmony_ci 1236e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 1237e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1238e41f4b71Sopenharmony_ci listener.onDataDelete(index); 1239e41f4b71Sopenharmony_ci }) 1240e41f4b71Sopenharmony_ci } 1241e41f4b71Sopenharmony_ci 1242e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 1243e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1244e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 1245e41f4b71Sopenharmony_ci }) 1246e41f4b71Sopenharmony_ci } 1247e41f4b71Sopenharmony_ci} 1248e41f4b71Sopenharmony_ci 1249e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 1250e41f4b71Sopenharmony_ci private dataArray: StringData[] = []; 1251e41f4b71Sopenharmony_ci 1252e41f4b71Sopenharmony_ci public totalCount(): number { 1253e41f4b71Sopenharmony_ci return this.dataArray.length; 1254e41f4b71Sopenharmony_ci } 1255e41f4b71Sopenharmony_ci 1256e41f4b71Sopenharmony_ci public getData(index: number): StringData { 1257e41f4b71Sopenharmony_ci return this.dataArray[index]; 1258e41f4b71Sopenharmony_ci } 1259e41f4b71Sopenharmony_ci 1260e41f4b71Sopenharmony_ci public addData(index: number, data: StringData): void { 1261e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 1262e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 1263e41f4b71Sopenharmony_ci } 1264e41f4b71Sopenharmony_ci 1265e41f4b71Sopenharmony_ci public pushData(data: StringData): void { 1266e41f4b71Sopenharmony_ci this.dataArray.push(data); 1267e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 1268e41f4b71Sopenharmony_ci } 1269e41f4b71Sopenharmony_ci} 1270e41f4b71Sopenharmony_ci 1271e41f4b71Sopenharmony_ci@Observed 1272e41f4b71Sopenharmony_ciclass StringData { 1273e41f4b71Sopenharmony_ci message: string; 1274e41f4b71Sopenharmony_ci constructor(message: string) { 1275e41f4b71Sopenharmony_ci this.message = message; 1276e41f4b71Sopenharmony_ci } 1277e41f4b71Sopenharmony_ci} 1278e41f4b71Sopenharmony_ci 1279e41f4b71Sopenharmony_ci@Entry 1280e41f4b71Sopenharmony_ci@Component 1281e41f4b71Sopenharmony_cistruct MyComponent { 1282e41f4b71Sopenharmony_ci private moved: number[] = []; 1283e41f4b71Sopenharmony_ci @State data: MyDataSource = new MyDataSource(); 1284e41f4b71Sopenharmony_ci 1285e41f4b71Sopenharmony_ci aboutToAppear() { 1286e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 1287e41f4b71Sopenharmony_ci this.data.pushData(new StringData(`Hello ${i}`)); 1288e41f4b71Sopenharmony_ci } 1289e41f4b71Sopenharmony_ci } 1290e41f4b71Sopenharmony_ci 1291e41f4b71Sopenharmony_ci build() { 1292e41f4b71Sopenharmony_ci List({ space: 3 }) { 1293e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: StringData, index: number) => { 1294e41f4b71Sopenharmony_ci ListItem() { 1295e41f4b71Sopenharmony_ci ChildComponent({data: item}) 1296e41f4b71Sopenharmony_ci } 1297e41f4b71Sopenharmony_ci .onClick(() => { 1298e41f4b71Sopenharmony_ci item.message += '0'; 1299e41f4b71Sopenharmony_ci }) 1300e41f4b71Sopenharmony_ci }, (item: StringData, index: number) => index.toString()) 1301e41f4b71Sopenharmony_ci }.cachedCount(5) 1302e41f4b71Sopenharmony_ci } 1303e41f4b71Sopenharmony_ci} 1304e41f4b71Sopenharmony_ci 1305e41f4b71Sopenharmony_ci@Component 1306e41f4b71Sopenharmony_cistruct ChildComponent { 1307e41f4b71Sopenharmony_ci @ObjectLink data: StringData 1308e41f4b71Sopenharmony_ci build() { 1309e41f4b71Sopenharmony_ci Row() { 1310e41f4b71Sopenharmony_ci Text(this.data.message).fontSize(50) 1311e41f4b71Sopenharmony_ci .onAppear(() => { 1312e41f4b71Sopenharmony_ci console.info("appear:" + this.data.message) 1313e41f4b71Sopenharmony_ci }) 1314e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 1315e41f4b71Sopenharmony_ci } 1316e41f4b71Sopenharmony_ci} 1317e41f4b71Sopenharmony_ci``` 1318e41f4b71Sopenharmony_ci 1319e41f4b71Sopenharmony_ci此时点击`LazyForEach`子组件改变`item.message`时,重渲染依赖的是`ChildComponent`的`@ObjectLink`成员变量对其子属性的监听,此时框架只会刷新`Text(this.data.message)`,不会去重建整个`ListItem`子组件。 1320e41f4b71Sopenharmony_ci 1321e41f4b71Sopenharmony_ci**图10** LazyForEach改变数据子属性 1322e41f4b71Sopenharmony_ci 1323e41f4b71Sopenharmony_ci 1324e41f4b71Sopenharmony_ci## 拖拽排序 1325e41f4b71Sopenharmony_ci当LazyForEach在List组件下使用,并且设置了onMove事件,可以使能拖拽排序。拖拽排序离手后,如果数据位置发生变化,则会触发onMove事件,上报数据移动原始索引号和目标索引号。在onMove事件中,需要根据上报的起始索引号和目标索引号修改数据源。onMove中修改数据源不需要调用DataChangeListener中接口通知数据源变化。 1326e41f4b71Sopenharmony_ci 1327e41f4b71Sopenharmony_ci```ts 1328e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 1329e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1330e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 1331e41f4b71Sopenharmony_ci 1332e41f4b71Sopenharmony_ci public totalCount(): number { 1333e41f4b71Sopenharmony_ci return 0; 1334e41f4b71Sopenharmony_ci } 1335e41f4b71Sopenharmony_ci 1336e41f4b71Sopenharmony_ci public getData(index: number): string { 1337e41f4b71Sopenharmony_ci return this.originDataArray[index]; 1338e41f4b71Sopenharmony_ci } 1339e41f4b71Sopenharmony_ci 1340e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 1341e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 1342e41f4b71Sopenharmony_ci console.info('add listener'); 1343e41f4b71Sopenharmony_ci this.listeners.push(listener); 1344e41f4b71Sopenharmony_ci } 1345e41f4b71Sopenharmony_ci } 1346e41f4b71Sopenharmony_ci 1347e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 1348e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 1349e41f4b71Sopenharmony_ci if (pos >= 0) { 1350e41f4b71Sopenharmony_ci console.info('remove listener'); 1351e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 1352e41f4b71Sopenharmony_ci } 1353e41f4b71Sopenharmony_ci } 1354e41f4b71Sopenharmony_ci 1355e41f4b71Sopenharmony_ci notifyDataReload(): void { 1356e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1357e41f4b71Sopenharmony_ci listener.onDataReloaded(); 1358e41f4b71Sopenharmony_ci }) 1359e41f4b71Sopenharmony_ci } 1360e41f4b71Sopenharmony_ci 1361e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 1362e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1363e41f4b71Sopenharmony_ci listener.onDataAdd(index); 1364e41f4b71Sopenharmony_ci }) 1365e41f4b71Sopenharmony_ci } 1366e41f4b71Sopenharmony_ci 1367e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 1368e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1369e41f4b71Sopenharmony_ci listener.onDataChange(index); 1370e41f4b71Sopenharmony_ci }) 1371e41f4b71Sopenharmony_ci } 1372e41f4b71Sopenharmony_ci 1373e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 1374e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1375e41f4b71Sopenharmony_ci listener.onDataDelete(index); 1376e41f4b71Sopenharmony_ci }) 1377e41f4b71Sopenharmony_ci } 1378e41f4b71Sopenharmony_ci 1379e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 1380e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1381e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 1382e41f4b71Sopenharmony_ci }) 1383e41f4b71Sopenharmony_ci } 1384e41f4b71Sopenharmony_ci} 1385e41f4b71Sopenharmony_ci 1386e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 1387e41f4b71Sopenharmony_ci private dataArray: string[] = []; 1388e41f4b71Sopenharmony_ci 1389e41f4b71Sopenharmony_ci public totalCount(): number { 1390e41f4b71Sopenharmony_ci return this.dataArray.length; 1391e41f4b71Sopenharmony_ci } 1392e41f4b71Sopenharmony_ci 1393e41f4b71Sopenharmony_ci public getData(index: number): string { 1394e41f4b71Sopenharmony_ci return this.dataArray[index]; 1395e41f4b71Sopenharmony_ci } 1396e41f4b71Sopenharmony_ci 1397e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 1398e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 1399e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 1400e41f4b71Sopenharmony_ci } 1401e41f4b71Sopenharmony_ci 1402e41f4b71Sopenharmony_ci public moveDataWithoutNotify(from: number, to: number): void { 1403e41f4b71Sopenharmony_ci let tmp = this.dataArray.splice(from, 1); 1404e41f4b71Sopenharmony_ci this.dataArray.splice(to, 0, tmp[0]) 1405e41f4b71Sopenharmony_ci } 1406e41f4b71Sopenharmony_ci 1407e41f4b71Sopenharmony_ci public pushData(data: string): void { 1408e41f4b71Sopenharmony_ci this.dataArray.push(data); 1409e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 1410e41f4b71Sopenharmony_ci } 1411e41f4b71Sopenharmony_ci 1412e41f4b71Sopenharmony_ci public deleteData(index: number): void { 1413e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 1414e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 1415e41f4b71Sopenharmony_ci } 1416e41f4b71Sopenharmony_ci} 1417e41f4b71Sopenharmony_ci 1418e41f4b71Sopenharmony_ci@Entry 1419e41f4b71Sopenharmony_ci@Component 1420e41f4b71Sopenharmony_cistruct Parent { 1421e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 1422e41f4b71Sopenharmony_ci 1423e41f4b71Sopenharmony_ci build() { 1424e41f4b71Sopenharmony_ci Row() { 1425e41f4b71Sopenharmony_ci List() { 1426e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string) => { 1427e41f4b71Sopenharmony_ci ListItem() { 1428e41f4b71Sopenharmony_ci Text(item.toString()) 1429e41f4b71Sopenharmony_ci .fontSize(16) 1430e41f4b71Sopenharmony_ci .textAlign(TextAlign.Center) 1431e41f4b71Sopenharmony_ci .size({height: 100, width: "100%"}) 1432e41f4b71Sopenharmony_ci }.margin(10) 1433e41f4b71Sopenharmony_ci .borderRadius(10) 1434e41f4b71Sopenharmony_ci .backgroundColor("#FFFFFFFF") 1435e41f4b71Sopenharmony_ci }, (item: string) => item) 1436e41f4b71Sopenharmony_ci .onMove((from:number, to:number)=>{ 1437e41f4b71Sopenharmony_ci this.data.moveDataWithoutNotify(from, to) 1438e41f4b71Sopenharmony_ci }) 1439e41f4b71Sopenharmony_ci } 1440e41f4b71Sopenharmony_ci .width('100%') 1441e41f4b71Sopenharmony_ci .height('100%') 1442e41f4b71Sopenharmony_ci .backgroundColor("#FFDCDCDC") 1443e41f4b71Sopenharmony_ci } 1444e41f4b71Sopenharmony_ci } 1445e41f4b71Sopenharmony_ci aboutToAppear(): void { 1446e41f4b71Sopenharmony_ci for (let i = 0; i < 100; i++) { 1447e41f4b71Sopenharmony_ci this.data.pushData(i.toString()) 1448e41f4b71Sopenharmony_ci } 1449e41f4b71Sopenharmony_ci } 1450e41f4b71Sopenharmony_ci} 1451e41f4b71Sopenharmony_ci``` 1452e41f4b71Sopenharmony_ci 1453e41f4b71Sopenharmony_ci**图11** LazyForEach拖拽排序效果图 1454e41f4b71Sopenharmony_ci 1455e41f4b71Sopenharmony_ci 1456e41f4b71Sopenharmony_ci## 常见使用问题 1457e41f4b71Sopenharmony_ci 1458e41f4b71Sopenharmony_ci### 渲染结果非预期 1459e41f4b71Sopenharmony_ci 1460e41f4b71Sopenharmony_ci ```ts 1461e41f4b71Sopenharmony_ci class BasicDataSource implements IDataSource { 1462e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1463e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 1464e41f4b71Sopenharmony_ci 1465e41f4b71Sopenharmony_ci public totalCount(): number { 1466e41f4b71Sopenharmony_ci return 0; 1467e41f4b71Sopenharmony_ci } 1468e41f4b71Sopenharmony_ci 1469e41f4b71Sopenharmony_ci public getData(index: number): string { 1470e41f4b71Sopenharmony_ci return this.originDataArray[index]; 1471e41f4b71Sopenharmony_ci } 1472e41f4b71Sopenharmony_ci 1473e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 1474e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 1475e41f4b71Sopenharmony_ci console.info('add listener'); 1476e41f4b71Sopenharmony_ci this.listeners.push(listener); 1477e41f4b71Sopenharmony_ci } 1478e41f4b71Sopenharmony_ci } 1479e41f4b71Sopenharmony_ci 1480e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 1481e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 1482e41f4b71Sopenharmony_ci if (pos >= 0) { 1483e41f4b71Sopenharmony_ci console.info('remove listener'); 1484e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 1485e41f4b71Sopenharmony_ci } 1486e41f4b71Sopenharmony_ci } 1487e41f4b71Sopenharmony_ci 1488e41f4b71Sopenharmony_ci notifyDataReload(): void { 1489e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1490e41f4b71Sopenharmony_ci listener.onDataReloaded(); 1491e41f4b71Sopenharmony_ci }) 1492e41f4b71Sopenharmony_ci } 1493e41f4b71Sopenharmony_ci 1494e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 1495e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1496e41f4b71Sopenharmony_ci listener.onDataAdd(index); 1497e41f4b71Sopenharmony_ci }) 1498e41f4b71Sopenharmony_ci } 1499e41f4b71Sopenharmony_ci 1500e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 1501e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1502e41f4b71Sopenharmony_ci listener.onDataChange(index); 1503e41f4b71Sopenharmony_ci }) 1504e41f4b71Sopenharmony_ci } 1505e41f4b71Sopenharmony_ci 1506e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 1507e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1508e41f4b71Sopenharmony_ci listener.onDataDelete(index); 1509e41f4b71Sopenharmony_ci }) 1510e41f4b71Sopenharmony_ci } 1511e41f4b71Sopenharmony_ci 1512e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 1513e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1514e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 1515e41f4b71Sopenharmony_ci }) 1516e41f4b71Sopenharmony_ci } 1517e41f4b71Sopenharmony_ci } 1518e41f4b71Sopenharmony_ci 1519e41f4b71Sopenharmony_ci class MyDataSource extends BasicDataSource { 1520e41f4b71Sopenharmony_ci private dataArray: string[] = []; 1521e41f4b71Sopenharmony_ci 1522e41f4b71Sopenharmony_ci public totalCount(): number { 1523e41f4b71Sopenharmony_ci return this.dataArray.length; 1524e41f4b71Sopenharmony_ci } 1525e41f4b71Sopenharmony_ci 1526e41f4b71Sopenharmony_ci public getData(index: number): string { 1527e41f4b71Sopenharmony_ci return this.dataArray[index]; 1528e41f4b71Sopenharmony_ci } 1529e41f4b71Sopenharmony_ci 1530e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 1531e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 1532e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 1533e41f4b71Sopenharmony_ci } 1534e41f4b71Sopenharmony_ci 1535e41f4b71Sopenharmony_ci public pushData(data: string): void { 1536e41f4b71Sopenharmony_ci this.dataArray.push(data); 1537e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 1538e41f4b71Sopenharmony_ci } 1539e41f4b71Sopenharmony_ci 1540e41f4b71Sopenharmony_ci public deleteData(index: number): void { 1541e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 1542e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 1543e41f4b71Sopenharmony_ci } 1544e41f4b71Sopenharmony_ci } 1545e41f4b71Sopenharmony_ci 1546e41f4b71Sopenharmony_ci @Entry 1547e41f4b71Sopenharmony_ci @Component 1548e41f4b71Sopenharmony_ci struct MyComponent { 1549e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 1550e41f4b71Sopenharmony_ci 1551e41f4b71Sopenharmony_ci aboutToAppear() { 1552e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 1553e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 1554e41f4b71Sopenharmony_ci } 1555e41f4b71Sopenharmony_ci } 1556e41f4b71Sopenharmony_ci 1557e41f4b71Sopenharmony_ci build() { 1558e41f4b71Sopenharmony_ci List({ space: 3 }) { 1559e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 1560e41f4b71Sopenharmony_ci ListItem() { 1561e41f4b71Sopenharmony_ci Row() { 1562e41f4b71Sopenharmony_ci Text(item).fontSize(50) 1563e41f4b71Sopenharmony_ci .onAppear(() => { 1564e41f4b71Sopenharmony_ci console.info("appear:" + item) 1565e41f4b71Sopenharmony_ci }) 1566e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 1567e41f4b71Sopenharmony_ci } 1568e41f4b71Sopenharmony_ci .onClick(() => { 1569e41f4b71Sopenharmony_ci // 点击删除子组件 1570e41f4b71Sopenharmony_ci this.data.deleteData(index); 1571e41f4b71Sopenharmony_ci }) 1572e41f4b71Sopenharmony_ci }, (item: string) => item) 1573e41f4b71Sopenharmony_ci }.cachedCount(5) 1574e41f4b71Sopenharmony_ci } 1575e41f4b71Sopenharmony_ci } 1576e41f4b71Sopenharmony_ci ``` 1577e41f4b71Sopenharmony_ci 1578e41f4b71Sopenharmony_ci **图12** LazyForEach删除数据非预期 1579e41f4b71Sopenharmony_ci  1580e41f4b71Sopenharmony_ci 1581e41f4b71Sopenharmony_ci 当我们多次点击子组件时,会发现删除的并不一定是我们点击的那个子组件。原因是当我们删除了某一个子组件后,位于该子组件对应的数据项之后的各数据项,其`index`均应减1,但实际上后续的数据项对应的子组件仍然使用的是最初分配的`index`,其`itemGenerator`中的`index`并没有发生变化,所以删除结果和预期不符。 1582e41f4b71Sopenharmony_ci 1583e41f4b71Sopenharmony_ci 修复代码如下所示。 1584e41f4b71Sopenharmony_ci 1585e41f4b71Sopenharmony_ci ```ts 1586e41f4b71Sopenharmony_ci class BasicDataSource implements IDataSource { 1587e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1588e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 1589e41f4b71Sopenharmony_ci 1590e41f4b71Sopenharmony_ci public totalCount(): number { 1591e41f4b71Sopenharmony_ci return 0; 1592e41f4b71Sopenharmony_ci } 1593e41f4b71Sopenharmony_ci 1594e41f4b71Sopenharmony_ci public getData(index: number): string { 1595e41f4b71Sopenharmony_ci return this.originDataArray[index]; 1596e41f4b71Sopenharmony_ci } 1597e41f4b71Sopenharmony_ci 1598e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 1599e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 1600e41f4b71Sopenharmony_ci console.info('add listener'); 1601e41f4b71Sopenharmony_ci this.listeners.push(listener); 1602e41f4b71Sopenharmony_ci } 1603e41f4b71Sopenharmony_ci } 1604e41f4b71Sopenharmony_ci 1605e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 1606e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 1607e41f4b71Sopenharmony_ci if (pos >= 0) { 1608e41f4b71Sopenharmony_ci console.info('remove listener'); 1609e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 1610e41f4b71Sopenharmony_ci } 1611e41f4b71Sopenharmony_ci } 1612e41f4b71Sopenharmony_ci 1613e41f4b71Sopenharmony_ci notifyDataReload(): void { 1614e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1615e41f4b71Sopenharmony_ci listener.onDataReloaded(); 1616e41f4b71Sopenharmony_ci }) 1617e41f4b71Sopenharmony_ci } 1618e41f4b71Sopenharmony_ci 1619e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 1620e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1621e41f4b71Sopenharmony_ci listener.onDataAdd(index); 1622e41f4b71Sopenharmony_ci }) 1623e41f4b71Sopenharmony_ci } 1624e41f4b71Sopenharmony_ci 1625e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 1626e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1627e41f4b71Sopenharmony_ci listener.onDataChange(index); 1628e41f4b71Sopenharmony_ci }) 1629e41f4b71Sopenharmony_ci } 1630e41f4b71Sopenharmony_ci 1631e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 1632e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1633e41f4b71Sopenharmony_ci listener.onDataDelete(index); 1634e41f4b71Sopenharmony_ci }) 1635e41f4b71Sopenharmony_ci } 1636e41f4b71Sopenharmony_ci 1637e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 1638e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1639e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 1640e41f4b71Sopenharmony_ci }) 1641e41f4b71Sopenharmony_ci } 1642e41f4b71Sopenharmony_ci } 1643e41f4b71Sopenharmony_ci 1644e41f4b71Sopenharmony_ci class MyDataSource extends BasicDataSource { 1645e41f4b71Sopenharmony_ci private dataArray: string[] = []; 1646e41f4b71Sopenharmony_ci 1647e41f4b71Sopenharmony_ci public totalCount(): number { 1648e41f4b71Sopenharmony_ci return this.dataArray.length; 1649e41f4b71Sopenharmony_ci } 1650e41f4b71Sopenharmony_ci 1651e41f4b71Sopenharmony_ci public getData(index: number): string { 1652e41f4b71Sopenharmony_ci return this.dataArray[index]; 1653e41f4b71Sopenharmony_ci } 1654e41f4b71Sopenharmony_ci 1655e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 1656e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 1657e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 1658e41f4b71Sopenharmony_ci } 1659e41f4b71Sopenharmony_ci 1660e41f4b71Sopenharmony_ci public pushData(data: string): void { 1661e41f4b71Sopenharmony_ci this.dataArray.push(data); 1662e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 1663e41f4b71Sopenharmony_ci } 1664e41f4b71Sopenharmony_ci 1665e41f4b71Sopenharmony_ci public deleteData(index: number): void { 1666e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 1667e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 1668e41f4b71Sopenharmony_ci } 1669e41f4b71Sopenharmony_ci 1670e41f4b71Sopenharmony_ci public reloadData(): void { 1671e41f4b71Sopenharmony_ci this.notifyDataReload(); 1672e41f4b71Sopenharmony_ci } 1673e41f4b71Sopenharmony_ci } 1674e41f4b71Sopenharmony_ci 1675e41f4b71Sopenharmony_ci @Entry 1676e41f4b71Sopenharmony_ci @Component 1677e41f4b71Sopenharmony_ci struct MyComponent { 1678e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 1679e41f4b71Sopenharmony_ci 1680e41f4b71Sopenharmony_ci aboutToAppear() { 1681e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 1682e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 1683e41f4b71Sopenharmony_ci } 1684e41f4b71Sopenharmony_ci } 1685e41f4b71Sopenharmony_ci 1686e41f4b71Sopenharmony_ci build() { 1687e41f4b71Sopenharmony_ci List({ space: 3 }) { 1688e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 1689e41f4b71Sopenharmony_ci ListItem() { 1690e41f4b71Sopenharmony_ci Row() { 1691e41f4b71Sopenharmony_ci Text(item).fontSize(50) 1692e41f4b71Sopenharmony_ci .onAppear(() => { 1693e41f4b71Sopenharmony_ci console.info("appear:" + item) 1694e41f4b71Sopenharmony_ci }) 1695e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 1696e41f4b71Sopenharmony_ci } 1697e41f4b71Sopenharmony_ci .onClick(() => { 1698e41f4b71Sopenharmony_ci // 点击删除子组件 1699e41f4b71Sopenharmony_ci this.data.deleteData(index); 1700e41f4b71Sopenharmony_ci // 重置所有子组件的index索引 1701e41f4b71Sopenharmony_ci this.data.reloadData(); 1702e41f4b71Sopenharmony_ci }) 1703e41f4b71Sopenharmony_ci }, (item: string, index: number) => item + index.toString()) 1704e41f4b71Sopenharmony_ci }.cachedCount(5) 1705e41f4b71Sopenharmony_ci } 1706e41f4b71Sopenharmony_ci } 1707e41f4b71Sopenharmony_ci ``` 1708e41f4b71Sopenharmony_ci 1709e41f4b71Sopenharmony_ci 在删除一个数据项后调用`reloadData`方法,重建后面的数据项,以达到更新`index`索引的目的。要保证`reloadData`方法重建数据项,必须保证数据项能生成新的key。这里用了`item + index.toString()`保证被删除数据项后面的数据项都被重建。如果用`item + Data.now().toString()`替代,那么所有数据项都生成新的key,导致所有数据项都被重建。这种方法,效果是一样的,只是性能略差。 1710e41f4b71Sopenharmony_ci 1711e41f4b71Sopenharmony_ci **图13** 修复LazyForEach删除数据非预期 1712e41f4b71Sopenharmony_ci  1713e41f4b71Sopenharmony_ci 1714e41f4b71Sopenharmony_ci### 重渲染时图片闪烁 1715e41f4b71Sopenharmony_ci 1716e41f4b71Sopenharmony_ci ```ts 1717e41f4b71Sopenharmony_ci class BasicDataSource implements IDataSource { 1718e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1719e41f4b71Sopenharmony_ci private originDataArray: StringData[] = []; 1720e41f4b71Sopenharmony_ci 1721e41f4b71Sopenharmony_ci public totalCount(): number { 1722e41f4b71Sopenharmony_ci return 0; 1723e41f4b71Sopenharmony_ci } 1724e41f4b71Sopenharmony_ci 1725e41f4b71Sopenharmony_ci public getData(index: number): StringData { 1726e41f4b71Sopenharmony_ci return this.originDataArray[index]; 1727e41f4b71Sopenharmony_ci } 1728e41f4b71Sopenharmony_ci 1729e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 1730e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 1731e41f4b71Sopenharmony_ci console.info('add listener'); 1732e41f4b71Sopenharmony_ci this.listeners.push(listener); 1733e41f4b71Sopenharmony_ci } 1734e41f4b71Sopenharmony_ci } 1735e41f4b71Sopenharmony_ci 1736e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 1737e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 1738e41f4b71Sopenharmony_ci if (pos >= 0) { 1739e41f4b71Sopenharmony_ci console.info('remove listener'); 1740e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 1741e41f4b71Sopenharmony_ci } 1742e41f4b71Sopenharmony_ci } 1743e41f4b71Sopenharmony_ci 1744e41f4b71Sopenharmony_ci notifyDataReload(): void { 1745e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1746e41f4b71Sopenharmony_ci listener.onDataReloaded(); 1747e41f4b71Sopenharmony_ci }) 1748e41f4b71Sopenharmony_ci } 1749e41f4b71Sopenharmony_ci 1750e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 1751e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1752e41f4b71Sopenharmony_ci listener.onDataAdd(index); 1753e41f4b71Sopenharmony_ci }) 1754e41f4b71Sopenharmony_ci } 1755e41f4b71Sopenharmony_ci 1756e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 1757e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1758e41f4b71Sopenharmony_ci listener.onDataChange(index); 1759e41f4b71Sopenharmony_ci }) 1760e41f4b71Sopenharmony_ci } 1761e41f4b71Sopenharmony_ci 1762e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 1763e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1764e41f4b71Sopenharmony_ci listener.onDataDelete(index); 1765e41f4b71Sopenharmony_ci }) 1766e41f4b71Sopenharmony_ci } 1767e41f4b71Sopenharmony_ci 1768e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 1769e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1770e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 1771e41f4b71Sopenharmony_ci }) 1772e41f4b71Sopenharmony_ci } 1773e41f4b71Sopenharmony_ci } 1774e41f4b71Sopenharmony_ci 1775e41f4b71Sopenharmony_ci class MyDataSource extends BasicDataSource { 1776e41f4b71Sopenharmony_ci private dataArray: StringData[] = []; 1777e41f4b71Sopenharmony_ci 1778e41f4b71Sopenharmony_ci public totalCount(): number { 1779e41f4b71Sopenharmony_ci return this.dataArray.length; 1780e41f4b71Sopenharmony_ci } 1781e41f4b71Sopenharmony_ci 1782e41f4b71Sopenharmony_ci public getData(index: number): StringData { 1783e41f4b71Sopenharmony_ci return this.dataArray[index]; 1784e41f4b71Sopenharmony_ci } 1785e41f4b71Sopenharmony_ci 1786e41f4b71Sopenharmony_ci public addData(index: number, data: StringData): void { 1787e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 1788e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 1789e41f4b71Sopenharmony_ci } 1790e41f4b71Sopenharmony_ci 1791e41f4b71Sopenharmony_ci public pushData(data: StringData): void { 1792e41f4b71Sopenharmony_ci this.dataArray.push(data); 1793e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 1794e41f4b71Sopenharmony_ci } 1795e41f4b71Sopenharmony_ci 1796e41f4b71Sopenharmony_ci public reloadData(): void { 1797e41f4b71Sopenharmony_ci this.notifyDataReload(); 1798e41f4b71Sopenharmony_ci } 1799e41f4b71Sopenharmony_ci } 1800e41f4b71Sopenharmony_ci 1801e41f4b71Sopenharmony_ci class StringData { 1802e41f4b71Sopenharmony_ci message: string; 1803e41f4b71Sopenharmony_ci imgSrc: Resource; 1804e41f4b71Sopenharmony_ci constructor(message: string, imgSrc: Resource) { 1805e41f4b71Sopenharmony_ci this.message = message; 1806e41f4b71Sopenharmony_ci this.imgSrc = imgSrc; 1807e41f4b71Sopenharmony_ci } 1808e41f4b71Sopenharmony_ci } 1809e41f4b71Sopenharmony_ci 1810e41f4b71Sopenharmony_ci @Entry 1811e41f4b71Sopenharmony_ci @Component 1812e41f4b71Sopenharmony_ci struct MyComponent { 1813e41f4b71Sopenharmony_ci private moved: number[] = []; 1814e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 1815e41f4b71Sopenharmony_ci 1816e41f4b71Sopenharmony_ci aboutToAppear() { 1817e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 1818e41f4b71Sopenharmony_ci this.data.pushData(new StringData(`Hello ${i}`, $r('app.media.img'))); 1819e41f4b71Sopenharmony_ci } 1820e41f4b71Sopenharmony_ci } 1821e41f4b71Sopenharmony_ci 1822e41f4b71Sopenharmony_ci build() { 1823e41f4b71Sopenharmony_ci List({ space: 3 }) { 1824e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: StringData, index: number) => { 1825e41f4b71Sopenharmony_ci ListItem() { 1826e41f4b71Sopenharmony_ci Column() { 1827e41f4b71Sopenharmony_ci Text(item.message).fontSize(50) 1828e41f4b71Sopenharmony_ci .onAppear(() => { 1829e41f4b71Sopenharmony_ci console.info("appear:" + item.message) 1830e41f4b71Sopenharmony_ci }) 1831e41f4b71Sopenharmony_ci Image(item.imgSrc) 1832e41f4b71Sopenharmony_ci .width(500) 1833e41f4b71Sopenharmony_ci .height(200) 1834e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 1835e41f4b71Sopenharmony_ci } 1836e41f4b71Sopenharmony_ci .onClick(() => { 1837e41f4b71Sopenharmony_ci item.message += '00'; 1838e41f4b71Sopenharmony_ci this.data.reloadData(); 1839e41f4b71Sopenharmony_ci }) 1840e41f4b71Sopenharmony_ci }, (item: StringData, index: number) => JSON.stringify(item)) 1841e41f4b71Sopenharmony_ci }.cachedCount(5) 1842e41f4b71Sopenharmony_ci } 1843e41f4b71Sopenharmony_ci } 1844e41f4b71Sopenharmony_ci ``` 1845e41f4b71Sopenharmony_ci 1846e41f4b71Sopenharmony_ci **图14** LazyForEach仅改变文字但是图片闪烁问题 1847e41f4b71Sopenharmony_ci  1848e41f4b71Sopenharmony_ci 1849e41f4b71Sopenharmony_ci 在我们点击`ListItem`子组件时,我们只改变了数据项的`message`属性,但是`LazyForEach`的刷新机制会导致整个`ListItem`被重建。由于`Image`组件是异步刷新,所以视觉上图片会发生闪烁。为了解决这种情况我们应该使用`@ObjectLink`和`@Observed`去单独刷新使用了`item.message`的`Text`组件。 1850e41f4b71Sopenharmony_ci 1851e41f4b71Sopenharmony_ci 修复代码如下所示。 1852e41f4b71Sopenharmony_ci 1853e41f4b71Sopenharmony_ci ```ts 1854e41f4b71Sopenharmony_ci class BasicDataSource implements IDataSource { 1855e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1856e41f4b71Sopenharmony_ci private originDataArray: StringData[] = []; 1857e41f4b71Sopenharmony_ci 1858e41f4b71Sopenharmony_ci public totalCount(): number { 1859e41f4b71Sopenharmony_ci return 0; 1860e41f4b71Sopenharmony_ci } 1861e41f4b71Sopenharmony_ci 1862e41f4b71Sopenharmony_ci public getData(index: number): StringData { 1863e41f4b71Sopenharmony_ci return this.originDataArray[index]; 1864e41f4b71Sopenharmony_ci } 1865e41f4b71Sopenharmony_ci 1866e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 1867e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 1868e41f4b71Sopenharmony_ci console.info('add listener'); 1869e41f4b71Sopenharmony_ci this.listeners.push(listener); 1870e41f4b71Sopenharmony_ci } 1871e41f4b71Sopenharmony_ci } 1872e41f4b71Sopenharmony_ci 1873e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 1874e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 1875e41f4b71Sopenharmony_ci if (pos >= 0) { 1876e41f4b71Sopenharmony_ci console.info('remove listener'); 1877e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 1878e41f4b71Sopenharmony_ci } 1879e41f4b71Sopenharmony_ci } 1880e41f4b71Sopenharmony_ci 1881e41f4b71Sopenharmony_ci notifyDataReload(): void { 1882e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1883e41f4b71Sopenharmony_ci listener.onDataReloaded(); 1884e41f4b71Sopenharmony_ci }) 1885e41f4b71Sopenharmony_ci } 1886e41f4b71Sopenharmony_ci 1887e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 1888e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1889e41f4b71Sopenharmony_ci listener.onDataAdd(index); 1890e41f4b71Sopenharmony_ci }) 1891e41f4b71Sopenharmony_ci } 1892e41f4b71Sopenharmony_ci 1893e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 1894e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1895e41f4b71Sopenharmony_ci listener.onDataChange(index); 1896e41f4b71Sopenharmony_ci }) 1897e41f4b71Sopenharmony_ci } 1898e41f4b71Sopenharmony_ci 1899e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 1900e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1901e41f4b71Sopenharmony_ci listener.onDataDelete(index); 1902e41f4b71Sopenharmony_ci }) 1903e41f4b71Sopenharmony_ci } 1904e41f4b71Sopenharmony_ci 1905e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 1906e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 1907e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 1908e41f4b71Sopenharmony_ci }) 1909e41f4b71Sopenharmony_ci } 1910e41f4b71Sopenharmony_ci } 1911e41f4b71Sopenharmony_ci 1912e41f4b71Sopenharmony_ci class MyDataSource extends BasicDataSource { 1913e41f4b71Sopenharmony_ci private dataArray: StringData[] = []; 1914e41f4b71Sopenharmony_ci 1915e41f4b71Sopenharmony_ci public totalCount(): number { 1916e41f4b71Sopenharmony_ci return this.dataArray.length; 1917e41f4b71Sopenharmony_ci } 1918e41f4b71Sopenharmony_ci 1919e41f4b71Sopenharmony_ci public getData(index: number): StringData { 1920e41f4b71Sopenharmony_ci return this.dataArray[index]; 1921e41f4b71Sopenharmony_ci } 1922e41f4b71Sopenharmony_ci 1923e41f4b71Sopenharmony_ci public addData(index: number, data: StringData): void { 1924e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 1925e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 1926e41f4b71Sopenharmony_ci } 1927e41f4b71Sopenharmony_ci 1928e41f4b71Sopenharmony_ci public pushData(data: StringData): void { 1929e41f4b71Sopenharmony_ci this.dataArray.push(data); 1930e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 1931e41f4b71Sopenharmony_ci } 1932e41f4b71Sopenharmony_ci } 1933e41f4b71Sopenharmony_ci 1934e41f4b71Sopenharmony_ci // @Observed类装饰器 和 @ObjectLink 用于在涉及嵌套对象或数组的场景中进行双向数据同步 1935e41f4b71Sopenharmony_ci @Observed 1936e41f4b71Sopenharmony_ci class StringData { 1937e41f4b71Sopenharmony_ci message: string; 1938e41f4b71Sopenharmony_ci imgSrc: Resource; 1939e41f4b71Sopenharmony_ci constructor(message: string, imgSrc: Resource) { 1940e41f4b71Sopenharmony_ci this.message = message; 1941e41f4b71Sopenharmony_ci this.imgSrc = imgSrc; 1942e41f4b71Sopenharmony_ci } 1943e41f4b71Sopenharmony_ci } 1944e41f4b71Sopenharmony_ci 1945e41f4b71Sopenharmony_ci @Entry 1946e41f4b71Sopenharmony_ci @Component 1947e41f4b71Sopenharmony_ci struct MyComponent { 1948e41f4b71Sopenharmony_ci // 用状态变量来驱动UI刷新,而不是通过Lazyforeach的api来驱动UI刷新 1949e41f4b71Sopenharmony_ci @State data: MyDataSource = new MyDataSource(); 1950e41f4b71Sopenharmony_ci 1951e41f4b71Sopenharmony_ci aboutToAppear() { 1952e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 1953e41f4b71Sopenharmony_ci this.data.pushData(new StringData(`Hello ${i}`, $r('app.media.img'))); 1954e41f4b71Sopenharmony_ci } 1955e41f4b71Sopenharmony_ci } 1956e41f4b71Sopenharmony_ci 1957e41f4b71Sopenharmony_ci build() { 1958e41f4b71Sopenharmony_ci List({ space: 3 }) { 1959e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: StringData, index: number) => { 1960e41f4b71Sopenharmony_ci ListItem() { 1961e41f4b71Sopenharmony_ci ChildComponent({data: item}) 1962e41f4b71Sopenharmony_ci } 1963e41f4b71Sopenharmony_ci .onClick(() => { 1964e41f4b71Sopenharmony_ci item.message += '0'; 1965e41f4b71Sopenharmony_ci }) 1966e41f4b71Sopenharmony_ci }, (item: StringData, index: number) => index.toString()) 1967e41f4b71Sopenharmony_ci }.cachedCount(5) 1968e41f4b71Sopenharmony_ci } 1969e41f4b71Sopenharmony_ci } 1970e41f4b71Sopenharmony_ci 1971e41f4b71Sopenharmony_ci @Component 1972e41f4b71Sopenharmony_ci struct ChildComponent { 1973e41f4b71Sopenharmony_ci @ObjectLink data: StringData 1974e41f4b71Sopenharmony_ci build() { 1975e41f4b71Sopenharmony_ci Column() { 1976e41f4b71Sopenharmony_ci Text(this.data.message).fontSize(50) 1977e41f4b71Sopenharmony_ci .onAppear(() => { 1978e41f4b71Sopenharmony_ci console.info("appear:" + this.data.message) 1979e41f4b71Sopenharmony_ci }) 1980e41f4b71Sopenharmony_ci Image(this.data.imgSrc) 1981e41f4b71Sopenharmony_ci .width(500) 1982e41f4b71Sopenharmony_ci .height(200) 1983e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 1984e41f4b71Sopenharmony_ci } 1985e41f4b71Sopenharmony_ci } 1986e41f4b71Sopenharmony_ci ``` 1987e41f4b71Sopenharmony_ci 1988e41f4b71Sopenharmony_ci **图15** 修复LazyForEach仅改变文字但是图片闪烁问题 1989e41f4b71Sopenharmony_ci  1990e41f4b71Sopenharmony_ci 1991e41f4b71Sopenharmony_ci### @ObjectLink属性变化UI未更新 1992e41f4b71Sopenharmony_ci 1993e41f4b71Sopenharmony_ci ```ts 1994e41f4b71Sopenharmony_ci class BasicDataSource implements IDataSource { 1995e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 1996e41f4b71Sopenharmony_ci private originDataArray: StringData[] = []; 1997e41f4b71Sopenharmony_ci 1998e41f4b71Sopenharmony_ci public totalCount(): number { 1999e41f4b71Sopenharmony_ci return 0; 2000e41f4b71Sopenharmony_ci } 2001e41f4b71Sopenharmony_ci 2002e41f4b71Sopenharmony_ci public getData(index: number): StringData { 2003e41f4b71Sopenharmony_ci return this.originDataArray[index]; 2004e41f4b71Sopenharmony_ci } 2005e41f4b71Sopenharmony_ci 2006e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 2007e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 2008e41f4b71Sopenharmony_ci console.info('add listener'); 2009e41f4b71Sopenharmony_ci this.listeners.push(listener); 2010e41f4b71Sopenharmony_ci } 2011e41f4b71Sopenharmony_ci } 2012e41f4b71Sopenharmony_ci 2013e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 2014e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 2015e41f4b71Sopenharmony_ci if (pos >= 0) { 2016e41f4b71Sopenharmony_ci console.info('remove listener'); 2017e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 2018e41f4b71Sopenharmony_ci } 2019e41f4b71Sopenharmony_ci } 2020e41f4b71Sopenharmony_ci 2021e41f4b71Sopenharmony_ci notifyDataReload(): void { 2022e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2023e41f4b71Sopenharmony_ci listener.onDataReloaded(); 2024e41f4b71Sopenharmony_ci }) 2025e41f4b71Sopenharmony_ci } 2026e41f4b71Sopenharmony_ci 2027e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 2028e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2029e41f4b71Sopenharmony_ci listener.onDataAdd(index); 2030e41f4b71Sopenharmony_ci }) 2031e41f4b71Sopenharmony_ci } 2032e41f4b71Sopenharmony_ci 2033e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 2034e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2035e41f4b71Sopenharmony_ci listener.onDataChange(index); 2036e41f4b71Sopenharmony_ci }) 2037e41f4b71Sopenharmony_ci } 2038e41f4b71Sopenharmony_ci 2039e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 2040e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2041e41f4b71Sopenharmony_ci listener.onDataDelete(index); 2042e41f4b71Sopenharmony_ci }) 2043e41f4b71Sopenharmony_ci } 2044e41f4b71Sopenharmony_ci 2045e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 2046e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2047e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 2048e41f4b71Sopenharmony_ci }) 2049e41f4b71Sopenharmony_ci } 2050e41f4b71Sopenharmony_ci } 2051e41f4b71Sopenharmony_ci 2052e41f4b71Sopenharmony_ci class MyDataSource extends BasicDataSource { 2053e41f4b71Sopenharmony_ci private dataArray: StringData[] = []; 2054e41f4b71Sopenharmony_ci 2055e41f4b71Sopenharmony_ci public totalCount(): number { 2056e41f4b71Sopenharmony_ci return this.dataArray.length; 2057e41f4b71Sopenharmony_ci } 2058e41f4b71Sopenharmony_ci 2059e41f4b71Sopenharmony_ci public getData(index: number): StringData { 2060e41f4b71Sopenharmony_ci return this.dataArray[index]; 2061e41f4b71Sopenharmony_ci } 2062e41f4b71Sopenharmony_ci 2063e41f4b71Sopenharmony_ci public addData(index: number, data: StringData): void { 2064e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 2065e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 2066e41f4b71Sopenharmony_ci } 2067e41f4b71Sopenharmony_ci 2068e41f4b71Sopenharmony_ci public pushData(data: StringData): void { 2069e41f4b71Sopenharmony_ci this.dataArray.push(data); 2070e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 2071e41f4b71Sopenharmony_ci } 2072e41f4b71Sopenharmony_ci } 2073e41f4b71Sopenharmony_ci 2074e41f4b71Sopenharmony_ci @Observed 2075e41f4b71Sopenharmony_ci class StringData { 2076e41f4b71Sopenharmony_ci message: NestedString; 2077e41f4b71Sopenharmony_ci constructor(message: NestedString) { 2078e41f4b71Sopenharmony_ci this.message = message; 2079e41f4b71Sopenharmony_ci } 2080e41f4b71Sopenharmony_ci } 2081e41f4b71Sopenharmony_ci 2082e41f4b71Sopenharmony_ci @Observed 2083e41f4b71Sopenharmony_ci class NestedString { 2084e41f4b71Sopenharmony_ci message: string; 2085e41f4b71Sopenharmony_ci constructor(message: string) { 2086e41f4b71Sopenharmony_ci this.message = message; 2087e41f4b71Sopenharmony_ci } 2088e41f4b71Sopenharmony_ci } 2089e41f4b71Sopenharmony_ci 2090e41f4b71Sopenharmony_ci @Entry 2091e41f4b71Sopenharmony_ci @Component 2092e41f4b71Sopenharmony_ci struct MyComponent { 2093e41f4b71Sopenharmony_ci private moved: number[] = []; 2094e41f4b71Sopenharmony_ci @State data: MyDataSource = new MyDataSource(); 2095e41f4b71Sopenharmony_ci 2096e41f4b71Sopenharmony_ci aboutToAppear() { 2097e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 2098e41f4b71Sopenharmony_ci this.data.pushData(new StringData(new NestedString(`Hello ${i}`))); 2099e41f4b71Sopenharmony_ci } 2100e41f4b71Sopenharmony_ci } 2101e41f4b71Sopenharmony_ci 2102e41f4b71Sopenharmony_ci build() { 2103e41f4b71Sopenharmony_ci List({ space: 3 }) { 2104e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: StringData, index: number) => { 2105e41f4b71Sopenharmony_ci ListItem() { 2106e41f4b71Sopenharmony_ci ChildComponent({data: item}) 2107e41f4b71Sopenharmony_ci } 2108e41f4b71Sopenharmony_ci .onClick(() => { 2109e41f4b71Sopenharmony_ci item.message.message += '0'; 2110e41f4b71Sopenharmony_ci }) 2111e41f4b71Sopenharmony_ci }, (item: StringData, index: number) => JSON.stringify(item) + index.toString()) 2112e41f4b71Sopenharmony_ci }.cachedCount(5) 2113e41f4b71Sopenharmony_ci } 2114e41f4b71Sopenharmony_ci } 2115e41f4b71Sopenharmony_ci 2116e41f4b71Sopenharmony_ci @Component 2117e41f4b71Sopenharmony_ci struct ChildComponent { 2118e41f4b71Sopenharmony_ci @ObjectLink data: StringData 2119e41f4b71Sopenharmony_ci build() { 2120e41f4b71Sopenharmony_ci Row() { 2121e41f4b71Sopenharmony_ci Text(this.data.message.message).fontSize(50) 2122e41f4b71Sopenharmony_ci .onAppear(() => { 2123e41f4b71Sopenharmony_ci console.info("appear:" + this.data.message.message) 2124e41f4b71Sopenharmony_ci }) 2125e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 2126e41f4b71Sopenharmony_ci } 2127e41f4b71Sopenharmony_ci } 2128e41f4b71Sopenharmony_ci ``` 2129e41f4b71Sopenharmony_ci 2130e41f4b71Sopenharmony_ci **图16** ObjectLink属性变化后UI未更新 2131e41f4b71Sopenharmony_ci  2132e41f4b71Sopenharmony_ci 2133e41f4b71Sopenharmony_ci @ObjectLink装饰的成员变量仅能监听到其子属性的变化,再深入嵌套的属性便无法观测到了,因此我们只能改变它的子属性去通知对应组件重新渲染,具体[请查看@ObjectLink与@Observed的详细使用方法和限制条件](./arkts-observed-and-objectlink.md)。 2134e41f4b71Sopenharmony_ci 2135e41f4b71Sopenharmony_ci 修复代码如下所示。 2136e41f4b71Sopenharmony_ci 2137e41f4b71Sopenharmony_ci ```ts 2138e41f4b71Sopenharmony_ci class BasicDataSource implements IDataSource { 2139e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 2140e41f4b71Sopenharmony_ci private originDataArray: StringData[] = []; 2141e41f4b71Sopenharmony_ci 2142e41f4b71Sopenharmony_ci public totalCount(): number { 2143e41f4b71Sopenharmony_ci return 0; 2144e41f4b71Sopenharmony_ci } 2145e41f4b71Sopenharmony_ci 2146e41f4b71Sopenharmony_ci public getData(index: number): StringData { 2147e41f4b71Sopenharmony_ci return this.originDataArray[index]; 2148e41f4b71Sopenharmony_ci } 2149e41f4b71Sopenharmony_ci 2150e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 2151e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 2152e41f4b71Sopenharmony_ci console.info('add listener'); 2153e41f4b71Sopenharmony_ci this.listeners.push(listener); 2154e41f4b71Sopenharmony_ci } 2155e41f4b71Sopenharmony_ci } 2156e41f4b71Sopenharmony_ci 2157e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 2158e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 2159e41f4b71Sopenharmony_ci if (pos >= 0) { 2160e41f4b71Sopenharmony_ci console.info('remove listener'); 2161e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 2162e41f4b71Sopenharmony_ci } 2163e41f4b71Sopenharmony_ci } 2164e41f4b71Sopenharmony_ci 2165e41f4b71Sopenharmony_ci notifyDataReload(): void { 2166e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2167e41f4b71Sopenharmony_ci listener.onDataReloaded(); 2168e41f4b71Sopenharmony_ci }) 2169e41f4b71Sopenharmony_ci } 2170e41f4b71Sopenharmony_ci 2171e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 2172e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2173e41f4b71Sopenharmony_ci listener.onDataAdd(index); 2174e41f4b71Sopenharmony_ci }) 2175e41f4b71Sopenharmony_ci } 2176e41f4b71Sopenharmony_ci 2177e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 2178e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2179e41f4b71Sopenharmony_ci listener.onDataChange(index); 2180e41f4b71Sopenharmony_ci }) 2181e41f4b71Sopenharmony_ci } 2182e41f4b71Sopenharmony_ci 2183e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 2184e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2185e41f4b71Sopenharmony_ci listener.onDataDelete(index); 2186e41f4b71Sopenharmony_ci }) 2187e41f4b71Sopenharmony_ci } 2188e41f4b71Sopenharmony_ci 2189e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 2190e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2191e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 2192e41f4b71Sopenharmony_ci }) 2193e41f4b71Sopenharmony_ci } 2194e41f4b71Sopenharmony_ci } 2195e41f4b71Sopenharmony_ci 2196e41f4b71Sopenharmony_ci class MyDataSource extends BasicDataSource { 2197e41f4b71Sopenharmony_ci private dataArray: StringData[] = []; 2198e41f4b71Sopenharmony_ci 2199e41f4b71Sopenharmony_ci public totalCount(): number { 2200e41f4b71Sopenharmony_ci return this.dataArray.length; 2201e41f4b71Sopenharmony_ci } 2202e41f4b71Sopenharmony_ci 2203e41f4b71Sopenharmony_ci public getData(index: number): StringData { 2204e41f4b71Sopenharmony_ci return this.dataArray[index]; 2205e41f4b71Sopenharmony_ci } 2206e41f4b71Sopenharmony_ci 2207e41f4b71Sopenharmony_ci public addData(index: number, data: StringData): void { 2208e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 2209e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 2210e41f4b71Sopenharmony_ci } 2211e41f4b71Sopenharmony_ci 2212e41f4b71Sopenharmony_ci public pushData(data: StringData): void { 2213e41f4b71Sopenharmony_ci this.dataArray.push(data); 2214e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 2215e41f4b71Sopenharmony_ci } 2216e41f4b71Sopenharmony_ci } 2217e41f4b71Sopenharmony_ci 2218e41f4b71Sopenharmony_ci @Observed 2219e41f4b71Sopenharmony_ci class StringData { 2220e41f4b71Sopenharmony_ci message: NestedString; 2221e41f4b71Sopenharmony_ci constructor(message: NestedString) { 2222e41f4b71Sopenharmony_ci this.message = message; 2223e41f4b71Sopenharmony_ci } 2224e41f4b71Sopenharmony_ci } 2225e41f4b71Sopenharmony_ci 2226e41f4b71Sopenharmony_ci @Observed 2227e41f4b71Sopenharmony_ci class NestedString { 2228e41f4b71Sopenharmony_ci message: string; 2229e41f4b71Sopenharmony_ci constructor(message: string) { 2230e41f4b71Sopenharmony_ci this.message = message; 2231e41f4b71Sopenharmony_ci } 2232e41f4b71Sopenharmony_ci } 2233e41f4b71Sopenharmony_ci 2234e41f4b71Sopenharmony_ci @Entry 2235e41f4b71Sopenharmony_ci @Component 2236e41f4b71Sopenharmony_ci struct MyComponent { 2237e41f4b71Sopenharmony_ci private moved: number[] = []; 2238e41f4b71Sopenharmony_ci @State data: MyDataSource = new MyDataSource(); 2239e41f4b71Sopenharmony_ci 2240e41f4b71Sopenharmony_ci aboutToAppear() { 2241e41f4b71Sopenharmony_ci for (let i = 0; i <= 20; i++) { 2242e41f4b71Sopenharmony_ci this.data.pushData(new StringData(new NestedString(`Hello ${i}`))); 2243e41f4b71Sopenharmony_ci } 2244e41f4b71Sopenharmony_ci } 2245e41f4b71Sopenharmony_ci 2246e41f4b71Sopenharmony_ci build() { 2247e41f4b71Sopenharmony_ci List({ space: 3 }) { 2248e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: StringData, index: number) => { 2249e41f4b71Sopenharmony_ci ListItem() { 2250e41f4b71Sopenharmony_ci ChildComponent({data: item}) 2251e41f4b71Sopenharmony_ci } 2252e41f4b71Sopenharmony_ci .onClick(() => { 2253e41f4b71Sopenharmony_ci // @ObjectLink装饰的成员变量仅能监听到其子属性的变化,再深入嵌套的属性便无法观测到 2254e41f4b71Sopenharmony_ci item.message = new NestedString(item.message.message + '0'); 2255e41f4b71Sopenharmony_ci }) 2256e41f4b71Sopenharmony_ci }, (item: StringData, index: number) => JSON.stringify(item) + index.toString()) 2257e41f4b71Sopenharmony_ci }.cachedCount(5) 2258e41f4b71Sopenharmony_ci } 2259e41f4b71Sopenharmony_ci } 2260e41f4b71Sopenharmony_ci 2261e41f4b71Sopenharmony_ci @Component 2262e41f4b71Sopenharmony_ci struct ChildComponent { 2263e41f4b71Sopenharmony_ci @ObjectLink data: StringData 2264e41f4b71Sopenharmony_ci build() { 2265e41f4b71Sopenharmony_ci Row() { 2266e41f4b71Sopenharmony_ci Text(this.data.message.message).fontSize(50) 2267e41f4b71Sopenharmony_ci .onAppear(() => { 2268e41f4b71Sopenharmony_ci console.info("appear:" + this.data.message.message) 2269e41f4b71Sopenharmony_ci }) 2270e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 2271e41f4b71Sopenharmony_ci } 2272e41f4b71Sopenharmony_ci } 2273e41f4b71Sopenharmony_ci ``` 2274e41f4b71Sopenharmony_ci 2275e41f4b71Sopenharmony_ci **图17** 修复ObjectLink属性变化后UI更新 2276e41f4b71Sopenharmony_ci  2277e41f4b71Sopenharmony_ci 2278e41f4b71Sopenharmony_ci### 在List内使用屏幕闪烁 2279e41f4b71Sopenharmony_ci在List的onScrollIndex方法中调用onDataReloaded有产生屏幕闪烁的风险。 2280e41f4b71Sopenharmony_ci 2281e41f4b71Sopenharmony_ci```ts 2282e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 2283e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 2284e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 2285e41f4b71Sopenharmony_ci 2286e41f4b71Sopenharmony_ci public totalCount(): number { 2287e41f4b71Sopenharmony_ci return 0; 2288e41f4b71Sopenharmony_ci } 2289e41f4b71Sopenharmony_ci 2290e41f4b71Sopenharmony_ci public getData(index: number): string { 2291e41f4b71Sopenharmony_ci return this.originDataArray[index]; 2292e41f4b71Sopenharmony_ci } 2293e41f4b71Sopenharmony_ci 2294e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 2295e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 2296e41f4b71Sopenharmony_ci console.info('add listener'); 2297e41f4b71Sopenharmony_ci this.listeners.push(listener); 2298e41f4b71Sopenharmony_ci } 2299e41f4b71Sopenharmony_ci } 2300e41f4b71Sopenharmony_ci 2301e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 2302e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 2303e41f4b71Sopenharmony_ci if (pos >= 0) { 2304e41f4b71Sopenharmony_ci console.info('remove listener'); 2305e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 2306e41f4b71Sopenharmony_ci } 2307e41f4b71Sopenharmony_ci } 2308e41f4b71Sopenharmony_ci 2309e41f4b71Sopenharmony_ci notifyDataReload(): void { 2310e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2311e41f4b71Sopenharmony_ci listener.onDataReloaded(); 2312e41f4b71Sopenharmony_ci }) 2313e41f4b71Sopenharmony_ci } 2314e41f4b71Sopenharmony_ci 2315e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 2316e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2317e41f4b71Sopenharmony_ci listener.onDataAdd(index); 2318e41f4b71Sopenharmony_ci }) 2319e41f4b71Sopenharmony_ci } 2320e41f4b71Sopenharmony_ci 2321e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 2322e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2323e41f4b71Sopenharmony_ci listener.onDataChange(index); 2324e41f4b71Sopenharmony_ci }) 2325e41f4b71Sopenharmony_ci } 2326e41f4b71Sopenharmony_ci 2327e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 2328e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2329e41f4b71Sopenharmony_ci listener.onDataDelete(index); 2330e41f4b71Sopenharmony_ci }) 2331e41f4b71Sopenharmony_ci } 2332e41f4b71Sopenharmony_ci 2333e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 2334e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2335e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 2336e41f4b71Sopenharmony_ci }) 2337e41f4b71Sopenharmony_ci } 2338e41f4b71Sopenharmony_ci 2339e41f4b71Sopenharmony_ci notifyDatasetChange(operations: DataOperation[]):void{ 2340e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2341e41f4b71Sopenharmony_ci listener.onDatasetChange(operations); 2342e41f4b71Sopenharmony_ci }) 2343e41f4b71Sopenharmony_ci } 2344e41f4b71Sopenharmony_ci} 2345e41f4b71Sopenharmony_ci 2346e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 2347e41f4b71Sopenharmony_ci private dataArray: string[] = []; 2348e41f4b71Sopenharmony_ci 2349e41f4b71Sopenharmony_ci public totalCount(): number { 2350e41f4b71Sopenharmony_ci return this.dataArray.length; 2351e41f4b71Sopenharmony_ci } 2352e41f4b71Sopenharmony_ci 2353e41f4b71Sopenharmony_ci public getData(index: number): string { 2354e41f4b71Sopenharmony_ci return this.dataArray[index]; 2355e41f4b71Sopenharmony_ci } 2356e41f4b71Sopenharmony_ci 2357e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 2358e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 2359e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 2360e41f4b71Sopenharmony_ci } 2361e41f4b71Sopenharmony_ci 2362e41f4b71Sopenharmony_ci public pushData(data: string): void { 2363e41f4b71Sopenharmony_ci this.dataArray.push(data); 2364e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 2365e41f4b71Sopenharmony_ci } 2366e41f4b71Sopenharmony_ci 2367e41f4b71Sopenharmony_ci public deleteData(index: number): void { 2368e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 2369e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 2370e41f4b71Sopenharmony_ci } 2371e41f4b71Sopenharmony_ci 2372e41f4b71Sopenharmony_ci public changeData(index: number): void { 2373e41f4b71Sopenharmony_ci this.notifyDataChange(index); 2374e41f4b71Sopenharmony_ci } 2375e41f4b71Sopenharmony_ci 2376e41f4b71Sopenharmony_ci operateData():void { 2377e41f4b71Sopenharmony_ci const totalCount = this.dataArray.length; 2378e41f4b71Sopenharmony_ci const batch=5; 2379e41f4b71Sopenharmony_ci for (let i = totalCount; i < totalCount + batch; i++) { 2380e41f4b71Sopenharmony_ci this.dataArray.push(`Hello ${i}`) 2381e41f4b71Sopenharmony_ci } 2382e41f4b71Sopenharmony_ci this.notifyDataReload(); 2383e41f4b71Sopenharmony_ci } 2384e41f4b71Sopenharmony_ci} 2385e41f4b71Sopenharmony_ci 2386e41f4b71Sopenharmony_ci@Entry 2387e41f4b71Sopenharmony_ci@Component 2388e41f4b71Sopenharmony_cistruct MyComponent { 2389e41f4b71Sopenharmony_ci private moved: number[] = []; 2390e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 2391e41f4b71Sopenharmony_ci 2392e41f4b71Sopenharmony_ci aboutToAppear() { 2393e41f4b71Sopenharmony_ci for (let i = 0; i <= 10; i++) { 2394e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 2395e41f4b71Sopenharmony_ci } 2396e41f4b71Sopenharmony_ci } 2397e41f4b71Sopenharmony_ci 2398e41f4b71Sopenharmony_ci build() { 2399e41f4b71Sopenharmony_ci List({ space: 3 }) { 2400e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 2401e41f4b71Sopenharmony_ci ListItem() { 2402e41f4b71Sopenharmony_ci Row() { 2403e41f4b71Sopenharmony_ci Text(item) 2404e41f4b71Sopenharmony_ci .width('100%') 2405e41f4b71Sopenharmony_ci .height(80) 2406e41f4b71Sopenharmony_ci .backgroundColor(Color.Gray) 2407e41f4b71Sopenharmony_ci .onAppear(() => { 2408e41f4b71Sopenharmony_ci console.info("appear:" + item) 2409e41f4b71Sopenharmony_ci }) 2410e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 2411e41f4b71Sopenharmony_ci } 2412e41f4b71Sopenharmony_ci }, (item: string) => item) 2413e41f4b71Sopenharmony_ci }.cachedCount(10) 2414e41f4b71Sopenharmony_ci .onScrollIndex((start, end, center) => { 2415e41f4b71Sopenharmony_ci if (end === this.data.totalCount() - 1) { 2416e41f4b71Sopenharmony_ci console.log('scroll to end') 2417e41f4b71Sopenharmony_ci this.data.operateData(); 2418e41f4b71Sopenharmony_ci } 2419e41f4b71Sopenharmony_ci }) 2420e41f4b71Sopenharmony_ci } 2421e41f4b71Sopenharmony_ci} 2422e41f4b71Sopenharmony_ci``` 2423e41f4b71Sopenharmony_ci 2424e41f4b71Sopenharmony_ci当List下拉到底的时候,屏闪效果如下图 2425e41f4b71Sopenharmony_ci 2426e41f4b71Sopenharmony_ci 2427e41f4b71Sopenharmony_ci用onDatasetChange代替onDataReloaded,不仅可以修复闪屏的问题,还能提升加载性能。 2428e41f4b71Sopenharmony_ci 2429e41f4b71Sopenharmony_ci```ts 2430e41f4b71Sopenharmony_ciclass BasicDataSource implements IDataSource { 2431e41f4b71Sopenharmony_ci private listeners: DataChangeListener[] = []; 2432e41f4b71Sopenharmony_ci private originDataArray: string[] = []; 2433e41f4b71Sopenharmony_ci 2434e41f4b71Sopenharmony_ci public totalCount(): number { 2435e41f4b71Sopenharmony_ci return 0; 2436e41f4b71Sopenharmony_ci } 2437e41f4b71Sopenharmony_ci 2438e41f4b71Sopenharmony_ci public getData(index: number): string { 2439e41f4b71Sopenharmony_ci return this.originDataArray[index]; 2440e41f4b71Sopenharmony_ci } 2441e41f4b71Sopenharmony_ci 2442e41f4b71Sopenharmony_ci registerDataChangeListener(listener: DataChangeListener): void { 2443e41f4b71Sopenharmony_ci if (this.listeners.indexOf(listener) < 0) { 2444e41f4b71Sopenharmony_ci console.info('add listener'); 2445e41f4b71Sopenharmony_ci this.listeners.push(listener); 2446e41f4b71Sopenharmony_ci } 2447e41f4b71Sopenharmony_ci } 2448e41f4b71Sopenharmony_ci 2449e41f4b71Sopenharmony_ci unregisterDataChangeListener(listener: DataChangeListener): void { 2450e41f4b71Sopenharmony_ci const pos = this.listeners.indexOf(listener); 2451e41f4b71Sopenharmony_ci if (pos >= 0) { 2452e41f4b71Sopenharmony_ci console.info('remove listener'); 2453e41f4b71Sopenharmony_ci this.listeners.splice(pos, 1); 2454e41f4b71Sopenharmony_ci } 2455e41f4b71Sopenharmony_ci } 2456e41f4b71Sopenharmony_ci 2457e41f4b71Sopenharmony_ci notifyDataReload(): void { 2458e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2459e41f4b71Sopenharmony_ci listener.onDataReloaded(); 2460e41f4b71Sopenharmony_ci }) 2461e41f4b71Sopenharmony_ci } 2462e41f4b71Sopenharmony_ci 2463e41f4b71Sopenharmony_ci notifyDataAdd(index: number): void { 2464e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2465e41f4b71Sopenharmony_ci listener.onDataAdd(index); 2466e41f4b71Sopenharmony_ci }) 2467e41f4b71Sopenharmony_ci } 2468e41f4b71Sopenharmony_ci 2469e41f4b71Sopenharmony_ci notifyDataChange(index: number): void { 2470e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2471e41f4b71Sopenharmony_ci listener.onDataChange(index); 2472e41f4b71Sopenharmony_ci }) 2473e41f4b71Sopenharmony_ci } 2474e41f4b71Sopenharmony_ci 2475e41f4b71Sopenharmony_ci notifyDataDelete(index: number): void { 2476e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2477e41f4b71Sopenharmony_ci listener.onDataDelete(index); 2478e41f4b71Sopenharmony_ci }) 2479e41f4b71Sopenharmony_ci } 2480e41f4b71Sopenharmony_ci 2481e41f4b71Sopenharmony_ci notifyDataMove(from: number, to: number): void { 2482e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2483e41f4b71Sopenharmony_ci listener.onDataMove(from, to); 2484e41f4b71Sopenharmony_ci }) 2485e41f4b71Sopenharmony_ci } 2486e41f4b71Sopenharmony_ci 2487e41f4b71Sopenharmony_ci notifyDatasetChange(operations: DataOperation[]):void{ 2488e41f4b71Sopenharmony_ci this.listeners.forEach(listener => { 2489e41f4b71Sopenharmony_ci listener.onDatasetChange(operations); 2490e41f4b71Sopenharmony_ci }) 2491e41f4b71Sopenharmony_ci } 2492e41f4b71Sopenharmony_ci} 2493e41f4b71Sopenharmony_ci 2494e41f4b71Sopenharmony_ciclass MyDataSource extends BasicDataSource { 2495e41f4b71Sopenharmony_ci private dataArray: string[] = []; 2496e41f4b71Sopenharmony_ci 2497e41f4b71Sopenharmony_ci public totalCount(): number { 2498e41f4b71Sopenharmony_ci return this.dataArray.length; 2499e41f4b71Sopenharmony_ci } 2500e41f4b71Sopenharmony_ci 2501e41f4b71Sopenharmony_ci public getData(index: number): string { 2502e41f4b71Sopenharmony_ci return this.dataArray[index]; 2503e41f4b71Sopenharmony_ci } 2504e41f4b71Sopenharmony_ci 2505e41f4b71Sopenharmony_ci public addData(index: number, data: string): void { 2506e41f4b71Sopenharmony_ci this.dataArray.splice(index, 0, data); 2507e41f4b71Sopenharmony_ci this.notifyDataAdd(index); 2508e41f4b71Sopenharmony_ci } 2509e41f4b71Sopenharmony_ci 2510e41f4b71Sopenharmony_ci public pushData(data: string): void { 2511e41f4b71Sopenharmony_ci this.dataArray.push(data); 2512e41f4b71Sopenharmony_ci this.notifyDataAdd(this.dataArray.length - 1); 2513e41f4b71Sopenharmony_ci } 2514e41f4b71Sopenharmony_ci 2515e41f4b71Sopenharmony_ci public deleteData(index: number): void { 2516e41f4b71Sopenharmony_ci this.dataArray.splice(index, 1); 2517e41f4b71Sopenharmony_ci this.notifyDataDelete(index); 2518e41f4b71Sopenharmony_ci } 2519e41f4b71Sopenharmony_ci 2520e41f4b71Sopenharmony_ci public changeData(index: number): void { 2521e41f4b71Sopenharmony_ci this.notifyDataChange(index); 2522e41f4b71Sopenharmony_ci } 2523e41f4b71Sopenharmony_ci 2524e41f4b71Sopenharmony_ci operateData():void { 2525e41f4b71Sopenharmony_ci const totalCount = this.dataArray.length; 2526e41f4b71Sopenharmony_ci const batch=5; 2527e41f4b71Sopenharmony_ci for (let i = totalCount; i < totalCount + batch; i++) { 2528e41f4b71Sopenharmony_ci this.dataArray.push(`Hello ${i}`) 2529e41f4b71Sopenharmony_ci } 2530e41f4b71Sopenharmony_ci // 替换 notifyDataReload 2531e41f4b71Sopenharmony_ci this.notifyDatasetChange([{type:DataOperationType.ADD, index: totalCount-1, count:batch}]) 2532e41f4b71Sopenharmony_ci } 2533e41f4b71Sopenharmony_ci} 2534e41f4b71Sopenharmony_ci 2535e41f4b71Sopenharmony_ci@Entry 2536e41f4b71Sopenharmony_ci@Component 2537e41f4b71Sopenharmony_cistruct MyComponent { 2538e41f4b71Sopenharmony_ci private moved: number[] = []; 2539e41f4b71Sopenharmony_ci private data: MyDataSource = new MyDataSource(); 2540e41f4b71Sopenharmony_ci 2541e41f4b71Sopenharmony_ci aboutToAppear() { 2542e41f4b71Sopenharmony_ci for (let i = 0; i <= 10; i++) { 2543e41f4b71Sopenharmony_ci this.data.pushData(`Hello ${i}`) 2544e41f4b71Sopenharmony_ci } 2545e41f4b71Sopenharmony_ci } 2546e41f4b71Sopenharmony_ci 2547e41f4b71Sopenharmony_ci build() { 2548e41f4b71Sopenharmony_ci List({ space: 3 }) { 2549e41f4b71Sopenharmony_ci LazyForEach(this.data, (item: string, index: number) => { 2550e41f4b71Sopenharmony_ci ListItem() { 2551e41f4b71Sopenharmony_ci Row() { 2552e41f4b71Sopenharmony_ci Text(item) 2553e41f4b71Sopenharmony_ci .width('100%') 2554e41f4b71Sopenharmony_ci .height(80) 2555e41f4b71Sopenharmony_ci .backgroundColor(Color.Gray) 2556e41f4b71Sopenharmony_ci .onAppear(() => { 2557e41f4b71Sopenharmony_ci console.info("appear:" + item) 2558e41f4b71Sopenharmony_ci }) 2559e41f4b71Sopenharmony_ci }.margin({ left: 10, right: 10 }) 2560e41f4b71Sopenharmony_ci } 2561e41f4b71Sopenharmony_ci }, (item: string) => item) 2562e41f4b71Sopenharmony_ci }.cachedCount(10) 2563e41f4b71Sopenharmony_ci .onScrollIndex((start, end, center) => { 2564e41f4b71Sopenharmony_ci if (end === this.data.totalCount() - 1) { 2565e41f4b71Sopenharmony_ci console.log('scroll to end') 2566e41f4b71Sopenharmony_ci this.data.operateData(); 2567e41f4b71Sopenharmony_ci } 2568e41f4b71Sopenharmony_ci }) 2569e41f4b71Sopenharmony_ci } 2570e41f4b71Sopenharmony_ci} 2571e41f4b71Sopenharmony_ci``` 2572e41f4b71Sopenharmony_ci 2573e41f4b71Sopenharmony_ci修复后的效果如下图 2574e41f4b71Sopenharmony_ci