目录
●渲染控制概述
●if/else:条件渲染
●ForEac:循环渲染
●LazyForEach:数据懒加载
●Repeat:循环渲染(推荐)
●ConnentSlot:混合开发
渲染控制概述
ArkUI通过自定义组件的build()函数和@builder装饰器声明式UI描述语句构建相应的的UI。在声明式描述语句中开发者除了使用系统组件外,还可以使用渲染语句来辅助UI的构建,这些渲染控制语句包括控制组件是否显示的条件语句,基于数组数据快速生成组件的虚幻渲染语句,针对大数据量的数据懒加载语句,针对混合模式开发的组件渲染语句。
if/else:条件渲染
ArkTS提供了渲染控制的能力,条件渲染可根据应用的不同状态,使用if、else和else if渲染对应状态下的UI内容。
使用规则
●支持if、else和else if语句
●if、else后跟随的条件语句可以使用状态变量
●允许在容器组件内使用,通过条件渲染语句构建不同的子组件。
●条件渲染语句在涉及到组件的父子关系时是"透明"的,当父组件和子组件之间存在一个或多个if语句时,必须遵守父组件关于子组件使用的规则
●每个分支内部的构建海曙必须遵循构建函数的规则,并创建一个或多个组件。无法创建组建的空构建函数会产生语法错误
●某些容器组件限制子组件的类型或数量,将条件渲染语句用于这些组件内时,这些限制同样应用于条件渲染语句内创建的组件。例如:Grid容器组件的子组件仅支持GridItem组件,在Grid内使用条件渲染语句时,条件渲染语句内仅允许使用GridItem组件。
更新机制
当if、else后跟随的状态判断中使用的状态变量值变化时,条件渲染语句会进行更新,更新步骤如下:
1.评估if和else if的状态判断条件,如果分支没有变化,无需执行以下步骤。如果分支有变化,则执行2、3步骤
2.删除此前构建的所有子组件
3.执行新分支的构造函数,将获取到的组件添加到if父容器中。如果缺少适用的else分支,则不构建然和内容。条件可以包括Typescript表达式。对于构造函数中的表达式,此类表达式不得更改应用程序状态。
ForEach:循环渲染
ForEach接口基于数组类型数据来进行需=循环渲染,需要与容器组件配合使用,且接口返回的数组应当是允许包含在ForEach父容器组件中的子组件。例如,ListItem组件要求ForEach的父容器组件必须为List组件
接口 描述
ForEach(
arr: Array,
itemGenerator: (item: Object, index: number) => void,
keyGenerator?: (item: Object, index: number) => string
)
以下是参数的详细说明:
键值生成规则
在ForEach循环渲染过程中,系统会为每个数组元素生成一个唯一且持久的键值,用于表示对应的组件。当这个键值发生变化时,ArkUI框架将视为该数组元素已被替换或修改,并会基于新的键值创建一个新的组件。
ForEach提供了一个名为keyGenerator的参数,这是一个函数,开发者可以通过它自定义键值生成规则。如果开发者没有定义keyGenerator函数,则ArkUI框架会使用默认的键值生成函数。
ArkUI框架对于ForEach的键值生成有一套特定的判断规则,这主要与itemGenerator函数的第二个参数index以及keyGenerator函数的第二个参数index有关,具体的键值生成规则判断逻辑如下图:
LazyForEach:数据懒加载
LazyForEach从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。当在滚动容器中使用了LazyForEach,框架会根据滚动容器可视区域按需创建组件,当组件划出可视区域外时,框架会进行组件销毁回收以降低内存占用。
接口描述
LazyForEach(
dataSource:IDataSource, //需要进行数据迭代的数据源
itemGenerator:(item:Object,index:number) => void,
keyGenerator:(item:Object,index:number) => string
):void
参数:
IDataSource类型说明
interface IDataSource {
totalCount():number; //获得数据总数
getData(index:number):Object; //获取索引值对应的数据
registerDataChangeListener(listener:DataChangeListener):void; //注册数据改变的监听器
unregisterDataChangeListener(listener:DataChangeListener):void; //注销数据改变的监听器
}
DataChangeListener类型说明
interface DataChangeListener {
onDataReloaded():void; //重新加载数据完成调用
onDataAdded(index:number):void; //添加数据完成后调用
onDataMoved(from:number,to:number):void; //数据移动起始位置与数据移动目标位置交换完成后调用
onDataDeleted(index:number):void; //删除数据完成后调用
onDataChaged(index:number):void; //改变数据完成后调用
onDataAdd(index:number):void; //添加数据完成后调用
onDataMove(from:number,to:number):void; //数据移动起始位置与数据移动目标位置交换完成后调用
onDataDelete(index:number):void; //删除数据完成后调用
onDataChange(index:number):void; //改变数据完成后调用
onDatasetChange(dataOperations:DataOperation[]):void; //批量数据处理后调用
}
DataOperation类型说明
type DataOperation =
DataAddOperation | //添加数据操作
DataDeleteOperation | //删除数据操作
DataChangeOperation | //改变数据操作
DataMoveOperation | //移动数据操作
DataExchangeOperation | //交换数据操作
DataReloadOperation //重载所有数据操作
DataAddOperation
interface DataAddOperation {
type:DataOperationType.ADD, //数据添加类型
index:number, //插入数据索引值
count?:number, //插入数量,默认值为1
ket?:string|Array<string> //为插入的数据分配键值
}
DataDeleteOperation
interface DataDeleteOperation{
type:DataOperationType.DELETE, //数据删除类型
index:number, //起始删除位置索引值
count?:number //删除数据数量,默认值为1
}
DataChangeOperation
interface DataChangeOperation{
type:DataOperationType.CHANGE, //数据改变类型
index:number, //改变的数据的索引值
key?:string //为改变的数据分配新的键值,默认使用原键值
}
DataMoveOperation
interface MoveIndex {
from:number; //起始移动位置
to:number; //目的移动位置
}
interface DataMoveOperation {
type:DataOperationType.MOVE, //数据移动类型
index:MoveIndex,
key?:string //为被移动的数据分配新的键值,默认使用原键值
}
DataExchangeOperation
interface ExchangeIndex {
start:number; //第一个交换位置
end:number; //第二个交换位置
}
interface ExchangeKey {
start:string; //为第一个交换的位置分配新的键值,默认使用原键值
end:string; //为第二个交换的位置分配新的键值,默认使用原键值
}
interface DataExchangeOperation {
type:DataOperationType.EXCHANGE, //数据交换类型
index:ExchangeIndex,
key?:ExchangeKey
}
DataReloadOperation
interface DataReloadOperation { //当onDataChange含有DataOperationType.RELOAD操作时,其余操作全部失效,框架会自己调用keyGenerator进行键值比对
type:DataOperationType.RELOAD //数据全部重新加载
}
使用限制
LazyForEach必须在容器组件内使用,仅有List、Grid、Swiper以及WaterFlow组件支持数据懒加载(可配置cachedCount属性,即只加载可视部分以及其前后少量数据用于缓冲),其他组件仍然是一次性加载所有数据。
LazyForEach在每次迭代中,必须创建且只允许创建一个子组件
生成的子组件必须是允许包含在LazyForEach父容器组件中的子组件
允许LazyForEach包含在if/else条件渲染语句中,也允许LazyForEach中出现if/else条件渲染语句
键值生成器必须针对每个数据生成唯一的值,如果键值相同,将导致键值相同的UI组件渲染出问题
LazyForEach必须使用DataChangeListener对象来进行更新,第一个参数dataSource使用状态变量时,状态变量改变不会触发LazyForEach的UI刷新
为了高性能渲染,通过DataChangeListener对象的onDataChange方法来更新UI时,需要生成不同于原来的键值来触发组件刷新
键值生成规则
在LazyForEach循环渲染过程中,系统会为每个item生成一个唯一且持久的键值,用于标识对应的组件。当这个键值变化时,ArkUI框架将视为该数组元素已被替换或修改,并会基于新的键值创建一个新的组件。
LazyForEach提供了一个名为keyGenerator的参数,这是一个函数,开发者可以通过它自定义键值的生成规则。如果开发者没有定义keyGenerator函数,则ArkUI框架会使用默认的键值生成函数,即(item: Object, index: number) => { return viewId + ‘-’ + index.toString(); }, viewId在编译器转换过程中生成,同一个LazyForEach组件内其viewId是一致的。
Repeat:循环渲染(推荐)
Repeat组件基于数组类型数据进行循环渲染,需要与容器组件配合使用,且接口返回的数组应当是允许包含在Repeat父容器组件中的子组件。
Repeat循环渲染和ForEach相比有两个区别,一是优化了部分更新场景下的渲染性能,二是组件生成函数的索引index由框架侧来维护。
接口描述
Repeat 组件构造
declare const Repeat:<T>(arr:Array<T>) => RepeatAttribute<T>
参数说明:
Repeat组件属性
declare class RepeatAttribute<T> {
each(itemGenerator:(repeatItem:RepeatItem<T>) => void) : RepeatAttribute<T>;
key(keyGenerator:(item:T,index:number) => string) : RepeatAttribute<T>;
}
参数说明:
RepeatItem 类型
interface RepeatItem<T> {
item:T,
index?:number
}
参数说明:
键值生成规则
在Repeat循环渲染过程中,系统会为每个数组元素生成一个唯一且持久的键值,用于标识对应的组件。当这个键值变化时,ArkUI框架将视为该数组元素已被替换或修改,会基于此去做对应的更新。若当前数组有数据项对应的键值与其他项重复,Repeat会为每一项数据补上index作为新的键值。
Repeat提供了key属性,参数是一个函数,开发者可以通过它自定义键值的生成规则。如果开发者没有调用key属性,则ArkUI框架会使用默认的键值生成函数。
ArkUI框架对于Repeat的键值生成有一套特定的判断规则,具体的键值生成规则判断逻辑如下图所示。
ContentSlot: 混合开发
用于渲染并管理Native层使用C-API创建的组件。
支持混合模式开发,当容器是ArkTS组件,子组件在Native侧创建时,推荐使用ContentSlot占位组件。
接口
ContentSlot组件接口
//当前开发者需要使用ArkUI提供的NodeContent作为管理器
ContentSlot(content:Content)
abstract class Content {
}
ContentSlotInterface
(content:Content):ContentSlotAttribute;
当内容添加到占位符组件时调用
系统能力: SystemCapability.ArkUI.ArkUI.Full
参数:
ContentSlotAttribute
定义ContentSlot属性,以防止不正确的递归使用ContentSlot
系统能力: SystemCapability.ArkUI.ArkUI.Full
Native侧接口
写在最后
●如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我两个小忙:
●点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
●关注小编,同时可以期待后续文章ing ,不定期分享原创知识。