• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 数据懒加载
2
3开发框架提供数据懒加载(LazyForEach组件)从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。LazyForEach定义如下:
4
5
6```
7LazyForEach(
8    dataSource: IDataSource,             // Data source to be iterated
9    itemGenerator: (item: any) => void,  // child component generator
10    keyGenerator?: (item: any) => string // (optional) Unique key generator, which is recommended.
11): void
12
13interface IDataSource {
14    totalCount(): number;                                             // Get total count of data
15    getData(index: number): any;                                      // Get single data by index
16    registerDataChangeListener(listener: DataChangeListener): void;   // Register listener to listening data changes
17    unregisterDataChangeListener(listener: DataChangeListener): void; // Unregister listener
18}
19
20interface DataChangeListener {
21    onDataReloaded(): void;                      // Called while data reloaded
22    onDataAdd(index: number): void;            // Called while single data added
23    onDataMove(from: number, to: number): void; // Called while single data moved
24    onDataDelete(index: number): void;          // Called while single data deleted
25    onDataChange(index: number): void;          // Called while single data changed
26}
27```
28
29
30## 接口
31
32
33### LazyForEach
34
35LazyForEach(dataSource: IDataSource, itemGenerator: (item: any) => void, keyGenerator?: (item: any) => string):void
36
37表1 参数说明
38
39| 参数名 | 参数类型 | 必填 | 默认值 | 参数描述 |
40| -------- | -------- | -------- | -------- | -------- |
41| dataSource | IDataSource | 是 | - | 实现IDataSource接口的对象,需要开发者实现相关接口。 |
42| itemGenerator | (item: any) => void | 是 | - | 生成子组件的lambda函数,为给定数组项生成一个或多个子组件,单个组件和子组件列表必须括在大括号“{....}”中。 |
43| keyGenerator | (item: any) => string | 否 | - | 匿名函数,用于键值生成,为给定数组项生成唯一且稳定的键值。当子项在数组中的位置更改时,子项的键值不得更改,当数组中的子项被新项替换时,被替换项的键值和新项的键值必须不同。键值生成器的功能是可选的,但是,为了使开发框架能够更好地识别数组更改,提高性能,建议提供。如将数组反向时,如果没有提供键值生成器,则LazyForEach中的所有节点都将重建。 |
44
45
46表2 IDataSource类型说明
47
48| 名称 | 描述 |
49| -------- | -------- |
50| totalCount(): number | 获取数据总数。 |
51| getData(index: number): any | 获取索引对应的数据。 |
52| registerDataChangeListener(listener:DataChangeListener): void | 注册改变数据的控制器。 |
53| unregisterDataChangeListener(listener:DataChangeListener): void | 注销改变数据的控制器。 |
54
55
56表3 DataChangeListener类型说明
57
58| 名称 | 描述 |
59| -------- | -------- |
60| onDataReloaded(): void | 重新加载所有数据。 |
61| onDataAdded(index:&nbsp;number):&nbsp;void <sup>(deprecated) </sup>| 通知组件index的位置有数据添加。 |
62| onDataMoved(from:&nbsp;number,&nbsp;to:&nbsp;number):&nbsp;void <sup>(deprecated) </sup>| 通知组件数据从from的位置移到to的位置。 |
63| onDataDeleted(index:&nbsp;number):&nbsp;void <sup>(deprecated) </sup>| 通知组件index的位置有数据删除。 |
64| onDataChanged(index:&nbsp;number):&nbsp;void <sup>(deprecated) </sup>| 通知组件index的位置有数据变化。 |
65| onDataAdd(index:&nbsp;number):&nbsp;void <sup>8+</sup> | 通知组件index的位置有数据添加。 |
66| onDataMove(from:&nbsp;number,&nbsp;to:&nbsp;number):&nbsp;void <sup>8+</sup> | 通知组件数据从from的位置移到to的位置。 |
67| onDataDelete(index:&nbsp;number):&nbsp;void <sup>8+</sup> | 通知组件index的位置有数据删除。 |
68| onDataChange(index:&nbsp;number):&nbsp;void <sup>8+</sup> | 通知组件index的位置有数据变化。 |
69
70
71> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
72> - 数据懒加载必须在容器组件内使用,且仅有List、Grid以及Swiper组件支持数据的懒加载(即只加载可视部分以及其前后少量数据用于缓冲),其他组件仍然是一次加载所有的数据;
73>
74> - LazyForEach在每次迭代中,必须且只允许创建一个子组件;
75>
76> - 生成的子组件必须允许在LazyForEach的父容器组件中;
77>
78> - 允许LazyForEach包含在if/else条件渲染语句中,不允许LazyForEach中出现if/else条件渲染语句;
79>
80> - 为了高性能渲染,通过DataChangeListener对象的onDataChange方法来更新UI时,仅itemGenerator中的UI描述的组件内使用了状态变量时,才会触发组件刷新;
81>
82> - 子项生成器函数的调用顺序不一定和数据源中的数据项相同,在开发过程中不要假设子项生成器和键值生成器函数是否执行以及执行顺序。如下示例可能无法正常工作:
83>   ```
84>   LazyForEach(dataSource, item => {Text(`${++counter}. item.label`)})
85>   ```
86>
87>   正确的示例如下:
88>
89>   ```
90>   LazyForEach(dataSource,
91>           item => Text(`${item.i}. item.data.label`)),
92>           item => item.data.id.toString())
93>   ```
94
95
96## 示例
97
98```
99// Basic implementation of IDataSource to handle data listener
100class BasicDataSource implements IDataSource {
101    private listeners: DataChangeListener[] = []
102
103    public totalCount(): number {
104        return 0
105    }
106    public getData(index: number): any {
107        return undefined
108    }
109
110    registerDataChangeListener(listener: DataChangeListener): void {
111        if (this.listeners.indexOf(listener) < 0) {
112            console.info('add listener')
113            this.listeners.push(listener)
114        }
115    }
116    unregisterDataChangeListener(listener: DataChangeListener): void {
117        const pos = this.listeners.indexOf(listener);
118        if (pos >= 0) {
119            console.info('remove listener')
120            this.listeners.splice(pos, 1)
121        }
122    }
123
124    notifyDataReload(): void {
125        this.listeners.forEach(listener => {
126            listener.onDataReloaded()
127        })
128    }
129    notifyDataAdd(index: number): void {
130        this.listeners.forEach(listener => {
131            listener.onDataAdd(index)
132        })
133    }
134    notifyDataChange(index: number): void {
135        this.listeners.forEach(listener => {
136            listener.onDataChange(index)
137        })
138    }
139    notifyDataDelete(index: number): void {
140        this.listeners.forEach(listener => {
141            listener.onDataDelete(index)
142        })
143    }
144    notifyDataMove(from: number, to: number): void {
145        this.listeners.forEach(listener => {
146            listener.onDataMove(from, to)
147        })
148    }
149}
150
151class MyDataSource extends BasicDataSource {
152    private dataArray: string[] = ['/path/image0', '/path/image1', '/path/image2', '/path/image3']
153
154    public totalCount(): number {
155        return this.dataArray.length
156    }
157    public getData(index: number): any {
158        return this.dataArray[index]
159    }
160
161    public addData(index: number, data: string): void {
162        this.dataArray.splice(index, 0, data)
163        this.notifyDataAdd(index)
164    }
165    public pushData(data: string): void {
166        this.dataArray.push(data)
167        this.notifyDataAdd(this.dataArray.length - 1)
168    }
169}
170
171@Entry
172@Component
173struct MyComponent {
174    private data: MyDataSource = new MyDataSource()
175    build() {
176        List({space: 3}) {
177            LazyForEach(this.data, (item: string) => {
178                ListItem() {
179                    Row() {
180                        Image(item).width("30%").height(50)
181                        Text(item).fontSize(20).margin({left:10})
182                    }.margin({left: 10, right: 10})
183                }
184                .onClick(()=>{
185                    this.data.pushData('/path/image' + this.data.totalCount())
186                })
187            }, item => item)
188        }
189    }
190}
191```
192