个人名片:
🐼作者简介:一名大三在校生,喜欢AI编程🎋
🐻❄️个人主页🥇:落798.
🐼个人WeChat:hmmwx53
🕊️系列专栏:🖼️
- 零基础学Java——小白入门必备
- 重识C语言——复习回顾
- 计算机网络体系———深度详讲
- HCIP数通工程师-刷题与实战
- 微信小程序开发——实战开发
- HarmonyOS 4.0 应用开发实战——实战开发
🐓每日一句:🍭我很忙,但我要忙的有意义!
欢迎评论 💬点赞👍🏻 收藏 📂加关注+
文章目录
- 一、ArkTS 快速入门
- 1.1 声明式UI
- 1.1.1 定义界面状态
- 1.1.2 描述界面显示效果
- 1.1.3 改变状态
- 1.1.4 总结
- 2.1 组件化
- 3.1 入门案例
- 3.1.1 案例效果
- 3.1.2 完整代码
- 4.1 语法说明
- 4.1.1 声明组件
- 4.1.2 自定义组件
- 4.1.3 渲染控制
- 4.1.4 循环渲染
- 欢迎添加微信,加入我的核心小队,请备注来意
一、ArkTS 快速入门
ArkTS
在继承了Typescript
语法的基础上,主要扩展了声明式UI
开发相关的能力。
1.1 声明式UI
声明式UI
是一种编写用户界面的范式。下面通过一个具体案例来学习这种开发范式,假如现在要实现如下界面
1.1.1 定义界面状态
按照声明式UI
的开发范式,首先需要分析和定义页面的各种状态,并声明相应的状态变量用于表示不同的状态。
当前案例中,界面共有两个状态,分别是开灯和关灯 状态,所以我们可以使用一个boolean
类型的变量来表示这两个状态,true表示开灯,false表示关灯。如下:
@State isOn: boolean = false;
说明:@State用于声明该变量为状态变量。
1.1.2 描述界面显示效果
在分析完界面状态后,我们需要准确的描述界面在不同状态下的显示效果。
在当前案例中,具体逻辑如下图所示
1.1.3 改变状态
在明确了界面在不同状态下的显示效果后,我们只需修改状态变量的值,就能触发界面的更新。
在当前案例中,若我们将isOn
的值改为true
,那么界面上就会显示开灯的图片,否则就会显示关灯的图片。
为了实现点击按钮开/关灯的效果,我们可以为按钮绑定点击事件:
● 当用户点击开灯按钮时,我们就将isOn的值改为true。● 当用于点击关灯按钮时,我们就将isOn的值改为false。
1.1.4 总结
以上就是声明式UI
开发范式的大致流程,下面为大家总结一下声明式UI
的核心思想
● 声明式描述
开发者只需描述在界面在不同状态下要呈现的最终效果,而无需关注界面变化的具体过程。
● 状态数据驱动界面更新
开发者只需修改状态变量的值,界面就会自动更新。
2.1 组件化
在鸿蒙开发中,组件是构成界面的最小单元,我们所看到的界面,都是由众多组件组合而成的,所以编写界面其实就是组合组件的过程,ArkTS
提供了很多的内置组件,例如:Text
、Button
、Image
等等;并且ArkTS
还支持自定义组件,让开发者可根据具体需求自定义组件中的内容。
3.1 入门案例
3.1.1 案例效果
案例的最终效果如下图所示
3.1.2 完整代码
案例的完整代码见Demos/entry/src/main/ets/pages/helloworld/light/solution/Light.ets
@Entry
@Component
struct LightPage {@State isOn: boolean = false;build() {Column({ space: 20 }) {if (this.isOn) {Image('pages/helloworld/light/solution/images/img_light.png').height(300).width(300).borderRadius(20)} else {Image('pages/helloworld/light/solution/images/img_dark.png').height(300).width(300).borderRadius(20)}Row({ space: 50 }) {Button('关灯').onClick(() => {this.isOn = false})Button('开灯').onClick(() => {this.isOn = true;})}}.height('100%').width('100%').justifyContent(FlexAlign.Center)}
}
4.1 语法说明
4.1.1 声明组件
下面通过一个相对简单的案例来系统的学习 ArkTS
声明组件的语法,案例的最终效果如下,完整代码见Demos/entry/src/main/ets/pages/helloworld/delete/DeleteButton.ets
声明组件的完整语法如下图所示
各部分语法说明如下
-
组件参数
如果组件的定义包含参数,可在组件名称后面的()
中配置相应参数。各组件支持的参数,可查看API
文档,查看方式如下- 首先将鼠标在相应组件悬停
- 点击
Show in API Reference
,就会弹出API
文档
- 首先将鼠标在相应组件悬停
-
子组件
如果组件支持子组件配置,可在()后的{}中添加子组件,若不支持子组件,则不需要写{}。 -
属性方法
属性方法用于配置组件的样式和其他属性,可以在组件声明的末尾进行链式调用。各组件支持的属性可查看 API 文档,除去每个组件的专有属性,还有各组件都能配置的通用属性,通用属性也可通过 API 文档查看。
-
事件方法
事件方法用于为组件绑定交互事件,可以在组件声明的末尾进行链式调用。各组件的支持的事件可查看 API 文档,除去每个组件的专有事件,还有各组件都支持的通用事件,通用事件也可通过 API 文档查看。
4.1.2 自定义组件
除去系统预置的组件外,ArkTS 还支持自定义组件。使用自定义组件,可使代码的结构更加清晰,并且能提高代码的复用性。
语法说明
自定义组件的语法如下图所示
各部分语法说明如下:
struct关键字
struct
是ArkTS
新增的用于自定义组件或者自定义弹窗的关键字。其声明的数据结构和TS
中的类十分相似,可包含属性和方法。
build方法build()
方法用于声明自定义组件的UI结构。
组件属性
组件属性可用作自定义组件的参数,使得自定义组件更为通用。@Compnent
装饰器
@Component
装饰器用于装饰struct关键字声明的数据结构。struct
被@Component
装饰后才具备组件化的能力。
注: 装饰器是Typescript
中的一种特殊语法,常用于装饰类、方法、属性,用于修改或扩展其原有的行为。
在学完自定义组件的语法之后,我们会发现前文案例中的每个页面实际上都是一个自定义组件。但是和自定义组件的语法相比,前边的每个案例还会多出一个@Entry
装饰器,那@Entry
的作用又是啥呢?
在鸿蒙应用中,每个页面都是由一些列组件组合而成的,并且这些组件都是逐层嵌套的,因此这些组件最终形成了一个组件树的结构,如下图所示
我们前边所编写的每个页面就相当于是组件树的根节点,而@Entry
装饰器的作用就是标识该组件为组件树的根节点,也就是一个页面的入口组件。
案例实操
现在需要对前文的开/关灯的案例做出如下改造,由于两个按钮的结构十分相似,所以可考虑自定义一个按钮组件,然后进行复用。
案例的完整代码见:Demos/entry/src/main/ets/pages/helloworld/custom/solution/Light.ets
4.1.3 渲染控制
条件渲染
概述 :条件渲染可根据应用的不同状态渲染不同的UI界面,例如前文的开/关灯案例,以及以下的播放/暂停案例,均可使用条件渲染实现。
案例的完整代码见:Demos/entry/src/main/ets/pages/helloworld/condition/solution/PlayAndPausePage.ets
语法说明
条件渲染的语法如下
if (...){//UI描述
}else if (...){//UI描述
}else{//UI描述
}
4.1.4 循环渲染
概述
循环渲染可使用
ForEach
语句基于一个数组来快速渲染一个组件列表,例如以下案例中的选项列表就可通过循环渲染实现。
案例的完整代码见:Demos/entry/src/main/ets/pages/helloworld/foreach/solution/FruitPage.ets
语法说明
ForEach
循环渲染的语法如下
各参数的含义如下
ForEach(arr: any[], itemGenerator: (item: any, index?: number) => void,keyGenerator?: (item: any, index?: number) => string
)
arr
需要进行循环渲染的数据源,必须为数组类型,例如上述案例中的
@State options: string[] = ["苹果", "桃子", "香蕉", "橘子"];
itemGenerator
组件生成函数,用于为arr数组中的每个元素创建对应的组件。该函数可接收两个参数,分别是item
:arr
数组中的数据项index
(可选):arr
数组中的数据项的索引
例如上述案例中的
(item: string) => {Button(item).width(100).backgroundColor(Color.Green).onClick(() => {this.answer = item;})}
keyGenerator
(可选):
key
生成函数,用于为arr数组中的每个数据项生成唯一的key
。
key的作用
ForEach
在数组发生变化(修改数组元素或者向数组增加或删除元素)时,需要重新渲染组件列表,在重新渲染时,它会尽量复用原来的组件对象,而不是为每个元素都重新创建组件对象。key
的作用就是辅助ForEach
完成组件对象的复用。
具体逻辑如下:
ForEach
在进行初次渲染时,会使用keyGenerator
为数组中的每个元素生成一个唯一的key
,并将key作为组件对象的标识。当数组发生变化导致ForEach
需要重新渲染时,ForEach
会再次使用keyGenerator
为每个元素重新生成一遍key
,然后ForEach
会检查新生成的key
在上次渲染时是否已经存在,若存在,ForEach
就会认为这个key
对应的数组元素没有发生变化,那它就会直接复用这个key
所对应的组件对象;若不存在,ForEach
就会认为这个key
对应的元素发生了变化,或者该元素为新增元素,此时,就会为该元素重新创建一个组件对象。
开发者可以通过keyGenerator
函数自定义key
的生成规则。如果开发者没有定义keyGenerator
函数,则系统会使用默认的key
生成函数,即
(item: any, index: number) => { return index + '__' + JSON.stringify(item); }
在某些情况下默认的key
生成函数,会导致界面渲染效率低下,此时可考虑通过keyGenerator
函数自定义生成逻辑,例如如下场景
状态变量数组定义如下
@State arr:string[] = ["zhangsan","lisi","wangwu"]
ForEach
语句如下
Column(){ForEach(this.arr,(item)=>{ Text(item) })
}
初次渲染时,每个元素对应的key
依次为0__"zhagnsan"、1__"lisi"、2__"wangwu"
。若现有一个操作是向arr数组头部插入新的元素,例如新元素为wanger,按照默认的key生成逻辑,插入新元素之后每个元素的key就会依次变为0__"wanger"、1__"zhagnsan"、2__"lisi"、3__"wangwu"
,也就是所有元素的key都发生了变化,因此UI界面更新时需要为每个元素都重新创建组件对象,即便原有的元素没有发生变化也无法复用之前的组件,这样一来就导致了性能浪费。此时我们就可以考虑提供第三个参数,如下
Column(){ForEach(this.arr, (item)=>{ Text(item) }, item => JSON.stringify(item))
}
欢迎添加微信,加入我的核心小队,请备注来意
👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇