因为项目可能会在后期要求渲染较多的数据项,且可能用于不同页面,故依据Api12的官方文档做了一个简单的懒加载组件,首先第一步是完成类的封装,这里的BasicData是对官方文档里面的直接复制,但这里对我们要使用的ProductInfoSource 这个类添加了一个更贴合我的项目的更改,我们加入了pushDataList来实现对数组的拼接。
class BasicDataSource implements IDataSource {
private listeners: DataChangeListener[] = [];
private originDataArray: Data[] | string[] = [];
public totalCount(): number {
return 0;
}
public getData(index: number): Data | string {
return this.originDataArray[index];
}
// 该方法为框架侧调用,为LazyForEach组件向其数据源处添加listener监听
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
console.info('add listener');
this.listeners.push(listener);
}
}
// 该方法为框架侧调用,为对应的LazyForEach组件在数据源处去除listener监听
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
console.info('remove listener');
this.listeners.splice(pos, 1);
}
}
// 通知LazyForEach组件需要重载所有子组件
notifyDataReload(): void {
this.listeners.forEach(listener => {
listener.onDataReloaded();
})
}
// 通知LazyForEach组件需要在index对应索引处添加子组件
notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
listener.onDataAdd(index);
})
}
// 通知LazyForEach组件在index对应索引处数据有变化,需要重建该子组件
notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index);
})
}
// 通知LazyForEach组件需要在index对应索引处删除该子组件
notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index);
})
}
// 通知LazyForEach组件将from索引和to索引处的子组件进行交换
notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
listener.onDataMove(from, to);
})
}
}
@Observed class ProductInfoSource extends BasicDataSource {
private dataArray: Data[] = [];
public totalCount(): number {
return this.dataArray.length;
}
public getData(index: number): Data {
return this.dataArray[index];
}
public addData(index: number, data: Data): void {
this.dataArray.splice(index, 0, data);
this.notifyDataAdd(index);
}
public pushData(data: Data): void {
this.dataArray.push(data);
this.notifyDataAdd(this.dataArray.length - 1);
}
public pushDataList(data: Data[]): void {
// 添加新数据
const startIndex = this.dataArray.length;
this.dataArray = [...this.dataArray, ...data];
// 通知每个新增数据项
for (let i = 0; i < data.length; i++) {
this.notifyDataAdd(startIndex + i);
}
}
}
然后编写子组件,这里只是简单的完成子组件的功能,之前使用@Prop装饰器一直无法正确渲染,后面找到了原因。
import { Data, ProductInfoSource } from '../interface/TypeFile'
@Component
export struct ProductItem {
// @State装饰器只能观察到第一层属性,这里使用@Prop无法更新数据
@ObjectLink data: ProductInfoSource;
// 若还有需要可以使用占位符实现row内容的替换
// 例如@BuilderParam Row_: () => void;
// 在build中使用this.Row_()实现对懒加载组件的复用
build() {
List({ space:10 }) {
LazyForEach(this.data, (item: Data) => {
ListItem() {
Row() {
Image((item.cover as Data[])[0].source as string)
Text(JSON.stringify(item))
}
}
})
}
}
}
然后在父组件中引用该组件就可以正常渲染了
build()
{
// .......
ProductItem({ data: this.productData })
// .......
}