【最新鸿蒙应用开发】——总结鸿蒙ArkTS渲染机制

ArkTS三种渲染控制机制

ArkUI通过自定义组件的build()函数和@builder装饰器中的声明式UI描述语句构建相应的UI。在声明式描述语句中开发者除了使用系统组件外,还可以使用渲染控制语句来辅助UI的构建,这些渲染控制语句包括控制组件是否显示的条件渲染语句,基于数组数据快速生成组件的循环渲染语句以及针对大数据量场景的数据懒加载语句。

1. if/else:条件渲染

ArkTS提供了渲染控制的能力。条件渲染可根据应用的不同状态,使用if、else和else if渲染对应状态下的UI内容。

1.1. 使用规则

  • 支持if、else和else if语句。

  • if、else if后跟随的条件语句可以使用状态变量。

  • 允许在容器组件内使用,通过条件渲染语句构建不同的子组件。

  • 条件渲染语句在涉及到组件的父子关系时是“透明”的,当父组件和子组件之间存在一个或多个if语句时,必须遵守父组件关于子组件使用的规则。

  • 每个分支内部的构建函数必须遵循构建函数的规则,并创建一个或多个组件。无法创建组件的空构建函数会产生语法错误。

  • 某些容器组件限制子组件的类型或数量,将条件渲染语句用于这些组件内时,这些限制将同样应用于条件渲染语句内创建的组件。例如,Grid容器组件的子组件仅支持GridItem组件,在Grid内使用条件渲染语句时,条件渲染语句内仅允许使用GridItem组件。

1.2. 更新机制

当if、else if后跟随的状态判断中使用的状态变量值变化时,条件渲染语句会进行更新,更新步骤如下:

  1. 评估if和else if的状态判断条件,如果分支没有变化,无需执行以下步骤。如果分支有变化,则执行2、3步骤:

  2. 删除此前构建的所有子组件。

  3. 执行新分支的构造函数,将获取到的组件添加到if父容器中。如果缺少适用的else分支,则不构建任何内容。

条件可以包括Typescript表达式。对于构造函数中的表达式,此类表达式不得更改应用程序状态。

1.3. 常用的if ... else

以下示例包含if ... else ...语句与拥有@State装饰变量的子组件。

@Component
struct CounterView {@State counter: number = 0;label: string = 'unknown';
​build() {Row() {Text(`${this.label}`)Button(`counter ${this.counter} +1`).onClick(() => {this.counter += 1;})}}
}
​
@Entry
@Component
struct MainView {@State toggle: boolean = true;
​build() {Column() {if (this.toggle) {CounterView({ label: 'CounterView #positive' })} else {CounterView({ label: 'CounterView #negative' })}Button(`toggle ${this.toggle}`).onClick(() => {this.toggle = !this.toggle;})}}
}

2. ForEach:循环渲染

太简单常用了,就不举例了。

用法

ForEach(arr: Array,itemGenerator: (item: any, index: number) => void,keyGenerator?: (item: any, index: number) => string
)

2.1. 键值生成规则

在ForEach循环渲染过程中,系统会为每个数组元素生成一个唯一且持久的键值,用于标识对应的组件。当这个键值变化时,ArkUI框架将视为该数组元素已被替换或修改,并会基于新的键值创建一个新的组件。

2.2. 组件创建规则

在确定键值生成规则后,ForEach的第二个参数itemGenerator函数会根据键值生成规则为数据源的每个数组项创建组件。组件的创建包括两种情况:ForEach首次渲染和ForEach非首次渲染。

2.2.1. 首次渲染

在ForEach首次渲染时,会根据前述键值生成规则为数据源的每个数组项生成唯一键值,并创建相应的组件。

2.2.2. 非首次渲染

在ForEach组件进行非首次渲染时,它会检查新生成的键值是否在上次渲染中已经存在。如果键值不存在,则会创建一个新的组件;如果键值存在,则不会创建新的组件,而是直接渲染该键值所对应的组件。

2.3. 使用建议

  • 尽量避免在最终的键值生成规则中包含数据项索引index,以防止出现渲染结果非预期和渲染性能降低。如果业务确实需要使用index,例如列表需要通过index进行条件渲染,开发者需要接受ForEach在改变数据源后重新创建组件所带来的性能损耗。

  • 为满足键值的唯一性,对于对象数据类型,建议使用对象数据中的唯一id作为键值。

  • 基本数据类型的数据项没有唯一ID属性。如果使用基本数据类型本身作为键值,必须确保数组项无重复。因此,对于数据源会发生变化的场景,建议将基本数据类型数组转化为具备唯一ID属性的对象数据类型数组,再使用ID属性作为键值生成规则。

  • 开发者在使用ForEach时应尽量避免最终键值生成规则中包含index。

3. LazyForEach:懒加载渲染

LazyForEach从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。当在滚动容器中使用了LazyForEach,框架会根据滚动容器可视区域按需创建组件,当组件滑出可视区域外时,框架会进行组件销毁回收以降低内存占用。

用法:

LazyForEach(dataSource: IDataSource,             // 需要进行数据迭代的数据源itemGenerator: (item: any, index: number) => void,  // 子组件生成函数keyGenerator?: (item: any, index: number) => string // 键值生成函数
): void
// IDataSource 需要提供给 LazyForEach 的数据源 必须要实现的接口
class BasicDataSource implements IDataSource {private listeners: DataChangeListener[] = new Array<DataChangeListener>();
​public totalCount(): number {return 0;}
​public getData(index: number): Object {return 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);})}
​notifyDataMove(from: number, to: number): void {this.listeners.forEach(listener => {listener.onDataMove(from, to);})}
}
​
// 将内部操纵数据的方法 类型,替换为我们希望的数据
class MyDataSource extends BasicDataSource {// 数据本身private dataArray: MkGoodsItem[] = [];
​// 总个数public totalCount(): number {return this.dataArray.length;}
​// 获取数据public getData(index: number): Object {return this.dataArray[index];}
​// 在指定的位置添加数据public addData(index: number, data: MkGoodsItem): void {this.dataArray.splice(index, 0, data);this.notifyDataAdd(index);}
​// 最佳数据public pushData(data: MkGoodsItem): void {this.dataArray.push(data);// notify 通知// DataAdd 添加数据// 通知数据源 数据背添加了this.notifyDataAdd(this.dataArray.length - 1);}
​// 清空数据public clear(): void {this.dataArray = [];}
}

4. 总结

4.1. 条件控制渲染:

  • 介绍:条件控制渲染语句运行直接在ArkUI容器组件内使用,通过条件渲染构建不同的子组件。

  • 机制:每个分支包含一个构建函数,会创建一个或多个子组件;当使用的状态变量发生变化后会卸载调之前的节点组件,重新构建另外的分支的组件。

  • 注意:在某些容器组件限制子组件的类型或数量的,条件渲染语句也会受限制,Grid组件内仅支持GridItem子组件;List组件只支持ListItem子组件;Scoll组件只能有一个根组件。

4.2. forEach循环渲染:

  • 介绍:和数组中的forEach方法原理类似,但是可以直接在ArkUI容器组件中使用,通过循环的形式创建多个子组件。

  • 机制:

    • 在ArkTS中,forEach有三个参数,分别是arritemGeneratorkeyGenerator。各参数的含义如下:

    • arr:需要进行循环渲染的数据源,必须为数组类型。

    • itemGenerator:组件生成函数,用于为arr数组中的每个元素创建对应的组件。该函数可接收两个参数,分别是:

      1. itemarr数组中的数据项。

      2. index`(可选) : arr数组中的数据项的索引。

    • keyGenerator(可选): key生成函数,用于为arr数组中的每个数据项生成唯一的key 。key的作用是辅助forEach完成组件对象的复用。

  • 注意:

    • 使用ForEach时应尽量避免最终键值生成规则中包含index。大白话:第二个参数和第三个参数要同步使用。

    • 如果数组id发生变化,比如某个元素被添加或者删除会导致索引乱序。需要使用三个参数来确定唯一id。

4.3. LazyForEach懒加载渲染:

  • 介绍:LazyForEach从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。当在滚动容器中使用了LazyForEach,框架会根据滚动容器可视区域按需创建组件,当组件滑出可视区域外时,框架会进行组件销毁回收以降低内存占用。

  • 机制:键值生成规则还有组件创建规则和ForEach渲染的机制差不多,不同的是数据源,通过实现内置接口IDataSource来监听注册数据的改变从而在每次迭代中只创建一个组件,并卸载之前的组件,达到降低内存的效果。

  • 注意:

    • 只能在特定的支持懒加载的组件中使用,比如List、Grid、Swiper、WaterFlow等。

    • 优化效果好,对一些长列表组件,轮播图等,特别有用。

4.4. LazyForEach和forEach的区别

在鸿蒙开发中,LazyForEach和forEach的主要区别在于它们的迭代方式和性能。 forEach 会立即迭代数组中的所有元素,并在每次迭代时执行提供的函数。这意味着无论元素是否实际被使用,都会进行迭代。 LazyForEach则采用惰性迭代的方式。它只会在需要时才迭代数组中的元素,即在元素被实际使用时才进行迭代。这种方式可以提高性能,特别是在处理大型数组或复杂的数据结构时,因为它避免了不必要的迭代操作。总的来说,LazyForEach更适合用于需要高性能和惰性计算的场景,而forEach则更适合用于简单的迭代操作。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/29307.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【大数据】gRPC、Flink、Kafka 分别是什么?

1. gRPC gRPC&#xff08;Google Remote Procedure Call&#xff09;是一个高性能、开源的远程过程调用&#xff08;RPC&#xff09;框架。它是由Google开发的&#xff0c;支持多种编程语言&#xff0c;并且广泛应用于微服务架构中。以下是gRPC的一些关键特点&#xff1a; 多语…

低代码结合自研项目打包发布

nginx配置 #user nobody; worker_processes 1;#error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info;#pid logs/nginx.pid;events {worker_connections 1024; }http {include mime.types;default_type applica…

麒麟Kylin | 操作系统的安装与管理

以下所使用的环境为&#xff1a;VMware Workstation 17 Pro、Kylin-Server-10-SP2-x86-Release-Build09-20210524 一、创建虚拟机 在VMware主机单击【创建新的虚拟机】 **在新建虚拟机向导中选择【自定义】&#xff0c;然后点击【下一步】 ** 保持默认选项&#xff0c;然后…

Vue 3 的 Teleport 组件实现跨层级通信

突破组件边界 - 使用 Vue 3 的 Teleport 组件实现跨层级通信 你可能已经熟悉了组件的基本概念:每个组件都是一个独立的单元,拥有自己的模板、样式和逻辑。但是,有时候我们需要在不同层级的组件之间进行交互,这就需要用到 Vue 3 中新引入的 Teleport 组件。 Teleport 组件可以…

CorelDRAW Graphics Suite下载2024最新版-CorelDRAW2024详细安装步骤

CorelDRAW​​ Graphics Suite官方版是款很多用户在工作中都会使用的矢量图形设计工具。CorelDRAW Graphics Suite正式版采用量身定制的界面和无与伦比的定制功能&#xff0c;畅享无缝设计经验。并且CorelDRAW Graphics Suite还可以广泛应用于商标设计、标志制作、模型绘制、插…

LangGraph自适应RAG

LangGraph自适应RAG 介绍索引LLMsweb 搜索工具graphgraph stategraph flowbuild graph执行 介绍 自适应 RAG 是一种 RAG 策略&#xff0c;它将 (1) 查询分析 (2) 主动/自校正 RAG 结合起来。 在文章中&#xff0c;他们报告了查询分析到路由获取&#xff1a; No RetrievalSing…

采用PHP语言(医院安全不良事件上报系统源码)医院不良事件 各类事件分析、分类、处理流程

医疗安全不容忽视&#xff01; 医疗安全&#xff08;不良&#xff09;事件是指在临床诊疗活动中以及医院运行过程中&#xff0c;任何可能影响患者的诊疗结果、增加患者的痛苦和负担并可能引发医疗纠纷或医疗事故&#xff0c;以及影响医疗工作的正常运行和医务人员人身安全的因…

什么是隐马尔可夫模型?

文章目录 一、说明二、玩具HMM&#xff1a;5′拼接位点识别三、那么&#xff0c;隐藏了什么&#xff1f;四、查找最佳状态路径五、超越最佳得分对齐六、制作更逼真的模型七、收获 关键词&#xff1a;hidden markov model 一、说明 被称为隐马尔可夫模型的统计模型是计算生物学…

libdrm 2.4.107 needed because amdgpu has the highest requirement

libdrm 2.4.107 needed because amdgpu has the highest requirement 1.问题分析解决 1.问题 Message: libdrm 2.4.107 needed because amdgpu has the highest requirement Run-time dependency libdrm_intel found: YES 2.4.107 Run-time dependency libdrm_amdgpu found: Y…

Day 25:1807. 替换字符串中的括号内容

Leetcode 1807. 替换字符串中的括号内容 给你一个字符串 s &#xff0c;它包含一些括号对&#xff0c;每个括号中包含一个 非空 的键。 比方说&#xff0c;字符串 “(name)is(age)yearsold” 中&#xff0c;有 两个 括号对&#xff0c;分别包含键 “name” 和 “age” 。 你知道…

Ansible介绍

一、Ansible概述 Ansible是一款开源的自动化运维工具&#xff0c;基于Python开发&#xff0c;主要用于批量系统配置、批量程序部署、批量运行命令等功能。它集合了众多运维工具的优点&#xff0c;并通过其高度模块化的特性&#xff0c;实现了灵活、可扩展的自动化运维管理。 …

ICMAN触摸芯片握手感应演示

随着科学技术的不断发展&#xff0c;触摸芯片在我们的生活中开始扮演着越来越多同时也越来越重要的角色&#xff0c;大到工业设备小到家用电器中都能找到它的身影。 相信大家都很好奇触摸芯片到底是怎样一个神奇的存在呢&#xff1f;那我们就来一探究竟。 要了解触摸芯片&…

ARDUINO NRF24L01

连线 5v 3.3皆可 gnd Optimized high speed nRF24L01 driver class documentation: Optimized High Speed Driver for nRF24L01() 2.4GHz Wireless Transceiver 同时下载同一个程序 案例默认引脚ce ces &#xff0c;7&#xff0c;8 可以 修改为 9,10 安装库 第一个示例 两…

热门开源项目推荐

以下是一些近年来非常受欢迎的开源项目&#xff0c;这些项目涵盖了多种编程语言和应用领域&#xff0c;适合不同需求和兴趣的开发者参与和学习。 1. TensorFlow 描述&#xff1a;一个用于机器学习的开源库&#xff0c;广泛应用于深度学习和人工智能项目。语言&#xff1a;Pyt…

【每日一题】522. 最长特殊序列 II

思路 由于数据量比较小&#xff0c;可以使用遍历的方法。最主要的就是按照题目中的定义&#xff0c;实现一个判断a字符串是否是b字符串的子串的方法。 选取当前字符串&#xff0c;遍历其他字符串&#xff0c;如果当前字符串是其他字符串中某一个的子串&#xff0c;跳过它&…

Java基础学习-方法

目录 方法基础概念 方法的格式&#xff1a; 案例&#xff1a;最简单方法的定义 案例&#xff1a;带参数的方法调用 案例&#xff1a;求圆的面积 带有返回值的方法&#xff1a; 方法注意点 方法的重载&#xff1a; ​编辑 案例&#xff1a;数组的遍历&#xff1a; 案例…

C++新特性复习1 版本11

参照来自于&#xff1a; cppreference.com 老实说&#xff0c;我是毕业不久就开始用C&#xff0c;原因就是VC&#xff0c;当时用来做界面。还好吧&#xff0c;不是觉得太难&#xff0c;起码对数学底子没有要求&#xff0c;后面偶尔也用用&#xff0c;但是整体还是C居多。现在项…

基于深度学习网络的USB摄像头实时视频采集与手势检测识别matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 系统架构 4.2 GoogLeNet网络简介 4.3 手势检测 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 训练过程如下&#xff1a; 将摄像头对准手势&#xff0c;然后进行…

【Kubernetes】k8s--安全机制

机制说明 Kubernetes 作为一个分布式集群的管理工具&#xff0c;保证集群的安全性是其一个重要的任务。API Server 是集群内部各个组件通信的中介&#xff0c; 也是外部控制的入口。所以 Kubernetes 的安全机制基本就是围绕保护 API Server 来设计的。 比如 kubectl 如果想向 …

Commons-Collections篇-CC2链分析

前言 3.1-3.2.1版本中TransformingComparator并没有去实现Serializable接口&#xff0c;是不可以被序列化的&#xff0c;所以我们重新搭建一个4.0的具有漏洞的CC环境 CC2链主要使用的和CC4一样&#xff0c;但是区别在于CC2避免了使用Transformer数组&#xff0c;没有使用Insta…