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![LazyForEach-Render-DifferentKey](./figures/LazyForEach-Render-DifferentKey.gif)
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![LazyForEach-Render-SameKey](./figures/LazyForEach-Render-SameKey.gif)
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![LazyForEach-Add-Data](./figures/LazyForEach-Add-Data.gif)
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![LazyForEach-Delete-Data](./figures/LazyForEach-Delete-Data.gif)
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![LazyForEach-Exchange-Data](./figures/LazyForEach-Exchange-Data.gif)
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![LazyForEach-Change-SingleData](./figures/LazyForEach-Change-SingleData.gif)
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![LazyForEach-Reload-Data](./figures/LazyForEach-Reload-Data.gif)
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![LazyForEach-Change-MultiData](./figures/LazyForEach-Change-MultiData.gif)  
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![LazyForEach-Change-MultiData2](./figures/LazyForEach-Change-MultiData2.gif)  
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![LazyForEach-Change-SubProperty](./figures/LazyForEach-Change-SubProperty.gif)
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![LazyForEach-Drag-Sort](figures/ForEach-Drag-Sort.gif)
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  ![LazyForEach-Render-Not-Expected](./figures/LazyForEach-Render-Not-Expected.gif)
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  ![LazyForEach-Render-Not-Expected-Repair](./figures/LazyForEach-Render-Not-Expected-Repair.gif)
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  ![LazyForEach-Image-Flush](./figures/LazyForEach-Image-Flush.gif)
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  ![LazyForEach-Image-Flush-Repair](./figures/LazyForEach-Image-Flush-Repair.gif)
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  ![LazyForEach-ObjectLink-NotRenderUI](./figures/LazyForEach-ObjectLink-NotRenderUI.gif)
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  ![LazyForEach-ObjectLink-NotRenderUI-Repair](./figures/LazyForEach-ObjectLink-NotRenderUI-Repair.gif)
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![LazyForEach-Screen-Flicker](figures/LazyForEach-Screen-Flicker.gif)
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![LazyForEach-Screen-Flicker-Repair](figures/LazyForEach-Screen-Flicker-Repair.gif)