HarmonyOS6 - ArkUI学习-下
学习目标
- 掌握常见组件的使用和实际应用
1. Slider组件
官网介绍地址:
https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-slider
Slider组件是滑动条组件,通常用于快速调节设置值,常用在音量调节、亮度调节、进度调节等场景。Slider组件的语法格式如下:
js
Slider(options)
options参数为一个对象,用于设置滑动条的各种配置属性,常用的配置属性如下
- value:用于设置当前进度值
- min:用于设置最小值,默认值为0
- max:用于设置最大值,默认值为100
- step:用于设置滑动条的滑动步长,默认值为1。当值小于0时,按默认值显示
- style:用于设置滑动条的滑块与滑轨显示样式,具体取值如下:
- SliderStyle.OutSet:默认值,表示滑块在滑轨上
- SliderStyle.InSet:表示滑块在滑轨内
- direction:用于设置滑动条滑动方向为水平方向还是竖直方向,具体取值如下:
- Axis.Horizontal:默认值,表示滑动方向为水平方向
- Axis.Vertical:表示滑动方向为竖直方向
- reverse:用于设置滑动条取值范围是否反向,横向滑动条默认为从左往右滑动,竖向滑动条默认为从上往下滑动
- 默认值为false,表示滑动条的取值范围是正向的
- 若值为true,表示滑动条的取值范围是反向的
下面通过代码演示如何配置Slider组件参数,示例代码如下:
js
@Entry
@Component
struct Index {
@State value: number = 30;
build() {
Column() {
Text('当前值:' + this.value)
.fontSize(30)
Slider({
min: 0,
max: 100,
value: this.value,
step: 10,
style: SliderStyle.InSet,
direction: Axis.Horizontal,
reverse: false
})
.blockColor('#ffff0000')
.trackColor('#ADD8E6')
.selectedColor('#4169E1')
.showSteps(true)
.showTips(true)
.onChange((value: number, mode: SliderChangeMode) => {
this.value = value;
})
}
.height('100%')
.width('100%')
}
}
页面效果如下:

Slider组件的常用属性如下表所示:
| 属性 | 说明 |
|---|---|
| blockColor | 用于设置滑块的颜色 |
| trackColor | 用于设置滑轨的背景颜色 |
| selectedColor | 用于设置滑轨的已滑动部分颜色 |
| showSteps | 用于设置当前是否显示步长刻度值,默认值为false,表示不显示步长刻度值;若值为true,表示显示步长刻度值 |
| showTips | 用于设置滑动时是否显示百分比气泡提示,默认值为false,表示不显示百分比气泡提示;若值为true,表示显示百分比气泡提示 |
| trackThickness | 用于设置滑轨的粗细。当配置属性style的值为SliderStyle.OutSet时,默认值为4;为SliderStyle.InSet时,默认值为20 |
2. Scroll组件
官网介绍地址:
https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-scroll
Scroll组件是可滚动的容器组件,当子组件中的布局尺寸超出了父容器组件的尺寸时,内容可以滚动。在Scroll组件中,只能放置一个子组件
Scroll组件的语法格式如下:
js
Scroll(scroller)//scroller参数用于控制Scroll组件的滚动
如果需要对滚动进行控制,可以导入Scroller对象,示例代码如下:
js
scroller: Scroller = new Scroller()
上述代码创建了一个Scroller对象,并将其赋值给scroller属性,以便进行滚动控制
一个Scroller对象代表一个控制器,它可以绑定到Scroll、List、Grid等容器组件上,但同一个控制器不可以控制多个容器组件
Scroller对象的常用属性如下表所示:
| 属性 | 说明 |
|---|---|
| scrollEdge | 用于设置滚动到容器的哪个边缘 |
| scrollPage | 用于设置滚动到下一页还是上一页,接收一个对象作为参数,该对象中包含next属性,表示是否向下翻页。如果next值为true,则表示向下翻页;如果next值为false,则表示向上翻页 |
scrollEdge属性的可选值如下:
- Edge.Top:表示垂直方向的顶部
- Edge.Bottom:表示垂直方向的底部
- Edge.Start:表示水平方向的起始位置
- Edge.End:表示水平方向的末尾位置
Scroll组件的常用属性如下表所示:
| 属性 | 说明 |
|---|---|
| scrollable | 用于设置滚动方向 |
| scrollBar | 用于设置滚动条状态 |
| scrollBarColor | 用于设置滚动条的颜色 |
| scrollBarWidth | 用于设置滚动条的宽度,不支持百分比。默认值为4 |
| edgeEffect | 用于设置边缘滑动效果 |
scrollable属性的常用可选值如下:
- ScrollDirection.Vertical:默认值,表示在垂直方向上滚动
- ScrollDirection.Horizontal:表示在水平方向上滚动
- ScrollDirection.None:表示不可滚动
scrollBar属性的常用可选值如下:
- BarState.Auto:默认值,表示按需显示,会在触摸时显示,2s后消失
- BarState.On:表示常驻显示
- BarState.Off:表示不显示。
edgeEffect属性的常用可选值如下:
- EdgeEffect.None:默认值,表示滑动到边缘后无效果
- EdgeEffect.Spring:表示滑动到边缘后可以根据初始速度或通过触摸事件继续滑动一段距离,松手后回弹
- EdgeEffect.Fade:表示滑动到边缘后会显示圆弧状的阴影
当用户进行滚动操作时,会触发组件区域变化事件onAreaChange,其事件处理程序接收2个参数: oldValue和newValue:
- oldValue表示目标组件变化之前的宽度、高度以及目标组件相对父组件和页面左上角的坐标位置
- newValue表示目标组件变化之后的宽度、高度以及目标组件相对父组件和页面左上角的坐标位置
案例代码如下:
js
@Entry
@Component
struct Index {
scroller: Scroller = new Scroller()
build() {
Scroll(this.scroller) {
Column() {
//顶部
Row() {
Text('顶部')
.fontColor('#ffffff')
.fontSize(20)
}
.padding(15)
.width('100%')
.backgroundColor('#ffff0000')
.justifyContent(FlexAlign.Center)
//中间
ForEach(Array.from({ length: 15 }), () => {
Row() {
Text('滚动区域内容')
.fontColor('#ffffff')
.fontSize(20)
}
.height(60)
.margin({ top: 15 })
.width('100%')
.backgroundColor('#ff6274ea')
.justifyContent(FlexAlign.Center)
})
//底部
Row() {
Text('底部')
.fontColor('#ffffff')
.fontSize(20)
}
.padding(15)
.width('100%')
.backgroundColor('#ffff0000')
.justifyContent(FlexAlign.Center)
}
}
.height('100%')
.scrollable(ScrollDirection.Vertical) //设置滚动方向
.scrollBar(BarState.Auto) //设置滚动条状态
.scrollBarColor('#ff000000')//设置滚动条的颜色
.scrollBarWidth(10)//设置滚动条的宽度
.edgeEffect(EdgeEffect.Spring)//设置边缘滑动效果
.align(Alignment.Top) //内容顶部对齐
}
}
页面效果如下:

3. List组件
官网介绍地址:
https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-list
- List组件是
列表组件,用于展示一系列具有相同宽度的列表项 - 列表项既可以纵向排列,也可以横向排列,适合呈现连续、多行的同类数据,例如图像和文本
- 当列表项数量过多,超出屏幕后,会自动出现滚动条,以便用户浏览
List组件可以包含子组件ListItem 和ListItemGroup
- ListItem组件用于展示列表中的具体项
- ListItemGroup组件用于实现列表项分组,其宽度默认充满List组件,必须配合List组件使用。
List组件的语法格式如下:
js
List(value)
value参数为一个对象,该对象包含的属性如下:
- space:用于设置列表项的间距
- initialIndex:用于设置列表项的初始索引位置
- scroller:用于控制List组件的滚动
List组件的常用属性如下表所示:
| 属性 | 说明 |
|---|---|
| listDirection | 用于设置列表项的排列方向 |
| divider | 用于设置列表项分割线的样式,默认无分割线 |
| edgeEffect | 用于设置列表的边缘滑动效果 |
listDirection属性的常用可选值如下:
- Axis.Vertical:默认值,表示纵向排列
- Axis.Horizontal:表示横向排列
divider属性的属性值为一个对象,该对象的常用的属性如下:
- strokeWidth:用于设置分割线的宽度
- color:用于设置分割线的颜色
- startMargin:用于设置分割线与列表项侧边起始端的距离
- endMargin:用于设置分割线与列表项侧边结束端的距离
edgeEffect属性的可选值与Scroll组件的edgeEffect属性的可选值相同,但其默认值为EdgeEffect.Spring
4. Flex组件
官网介绍地址:
https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-flex
- Flex组件是一个以
弹性方式布局子组件的容器组件,使用Flex组件可以实现弹性布局,也称为Flex布局 - 弹性布局主要由Flex容器(由Flex组件创建的容器)和子组件组成
- Flex容器包含两根轴:
主轴和交叉轴。默认情况下,主轴为水平方向,交叉轴为垂直方向 - 子组件默认
沿主轴排列,根据实际需要可以更改子组件的排列方式
主轴为水平方向的弹性布局结构如下图所示:

Flex组件的语法格式如下:
js
Flex(value)
value参数为一个对象,用于设置弹性布局相关的配置属性:
- direction属性用于设置Flex容器中子组件的排列方向,即主轴的方向,常用的可选值如下:
- FlexDirection.Row:默认值,主轴为从左到右的水平方向
- FlexDirection.RowReverse:主轴为从右到左的水平方向
- FlexDirection.Column:主轴为从上到下的垂直方向
- FlexDirection.ColumnReverse:主轴为从下到上的垂直方向。
- wrap属性用于设置Flex容器中子组件的换行方式,常用的可选值如下:
- FlexWrap.NoWrap:默认值,表示不允许换行,Flex容器为单行或单列,该情况下子组件可能会溢出Flex容器
- FlexWrap.Wrap:允许换行,如果Flex容器为多行或多列,子组件溢出的部分会被放置到新的一行,第一行显示在上方
- FlexWrap.WrapReverse:按照反方向换行,如果Flex容器为多行或多列,子组件溢出的部分会被放置到新的一行,第一行显示在下方
- justifyContent属性用于设置Flex容器中子组件在主轴方向上的对齐方式,常用的可选值如下:
- FlexAlign.Start:默认值,表示子组件在主轴方向上首端对齐,第一个子组件与首端边沿对齐,同时后续的子组件与前一个子组件对齐
- FlexAlign.Center:表示子组件在主轴方向上中心对齐,第一个子组件与首端边沿的距离与最后一个子组件与尾部边沿的距离相同
- FlexAlign.End:表示子组件在主轴方向上尾部对齐,最后一个子组件与尾部边沿对齐,其他子组件与后一个子组件对齐
- FlexAlign.SpaceBetween:表示在主轴方向上均匀分布子组件,相邻子组件之间距离相同。第一个子组件与首端边沿对齐,最后一个子组件与尾部边沿对齐
- FlexAlign.SpaceAround:表示在主轴方向上均匀分布子组件,相邻子组件之间距离相同。第一个子组件到首端边沿的距离和最后一个子组件到尾部边沿的距离是相邻子组件之间距离的一半
- FlexAlign.SpaceEvenly:表示在主轴方向上均匀分布子组件,相邻子组件之间距离、第一个子组件与首端边沿的距离、最后一个子组件与尾部边沿的距离相同
- alignItems属性用于设置Flex容器中子组件在交叉轴方向上的对齐方式,常用的可选值如下:
- ItemAlign.Stretch:表示子组件在Flex容器中,在交叉轴方向拉伸填充
- ItemAlign.Start:默认值,表示子组件在Flex容器中,在交叉轴方向首部对齐
- ItemAlign.Center:表示子组件在Flex容器中,在交叉轴方向居中对齐
- ItemAlign.End:表示子组件在Flex容器中,在交叉轴方向底部对齐
- ItemAlign.Auto:表示使用Flex容器中默认配置
- ItemAlign.Baseline:表示子组件在Flex容器中,在交叉轴方向文本基线对齐
- alignContent属性用于设置多轴线的对齐方式,适用于多行排列的情况,默认值为FlexAlign.Start,属性值参考justifyContent属性的说明
需求:
使用弹性布局,可以实现子元素沿水平方向排列,两端对齐,子元素间距平分,垂直方向上子元素居中的效果。
实现代码如下:
js
@Entry
@Component
struct FlexTest {
@State message: string = 'Hello World';
build() {
Column() {
Column({ space: 5 }) {
Flex({
direction: FlexDirection.Row, //子组件在Flex容器上排列的方向,即主轴的方向。
wrap: FlexWrap.NoWrap, //Flex容器是单行/列还是多行/列排列。
justifyContent: FlexAlign.SpaceBetween, //所有子组件在Flex容器主轴上的对齐格式。
alignItems: ItemAlign.Center//所有子组件在Flex容器交叉轴上的对齐格式。
}) {
Text('1').width(30).height(50).backgroundColor('#fff3cf79')
Text('2').width(30).height(50).backgroundColor('#fff3cf79')
Text('3').width(30).height(50).backgroundColor('#fff3cf79')
}
.height(70)
.width('90%')
.backgroundColor('#b0edee')
}.width('100%').margin({ top: 5 })
}.width('100%')
}
}

再看下面案例:

对应代码如下:
js
@Entry
@Component
struct FlexTest01 {
build() {
Flex({
direction: FlexDirection.Column, //子组件在Flex容器上排列的方向,即主轴的方向。
wrap: FlexWrap.NoWrap, //Flex容器是单行/列还是多行/列排列。
justifyContent: FlexAlign.SpaceBetween, //所有子组件在Flex容器主轴上的对齐格式。
alignItems: ItemAlign.Center//所有子组件在Flex容器交叉轴上的对齐格式。
}) {
Row() {
Text('商品详情')
}
.width('100%')
.height(50)
.backgroundColor('#ff93faca')
Row() {
Scroll() {
Text('内容区域:商品详情')
}
.height('100%')
.scrollable(ScrollDirection.Vertical) //设置滚动方向
.scrollBar(BarState.Off) //关闭滚动条
.align(Alignment.Top) //内容顶部对齐
.edgeEffect(EdgeEffect.Spring) //Scroll组件的边缘滑动效果,支持弹簧效果和阴影效果
}
.backgroundColor('#fff5eea4')
Row() {
Text('加入购物车')
.fontColor('#ffffff')
}
.width('100%')
.height(50)
.backgroundColor('#ff226ef1')
}
.backgroundColor('#ffffff')
.width('100%')
.height('100%')
}
}
5. Stack组件
官网介绍地址:
https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-stack
Stack组件是堆叠容器组件,其子组件按照顺序依次入栈,后一个子组件覆盖前一个子组件
Stack组件的语法格式如下:
js
Stack(value){...}
value参数为一个对象,对象中可以包含一个alignContent属性,用于设置子组件在堆叠方向 上的对齐方式
alignContent属性的常用属性值如下:
- Alignment.TopStart:表示子组件位于顶部起始端
- Alignment.Top:表示子组件位于顶部横向居中
- Alignment.TopEnd:表示子组件位于顶部尾端
- Alignment.Start:表示子组件位于起始端纵向居中
- Alignment.Center:默认值,表示子组件位于横向和纵向居中
- Alignment.End:表示子组件位于尾端纵向居中
- Alignment.BottomStart:表示子组件位于底部起始端
- Alignment.Bottom:表示子组件位于底部横向居中
- Alignment.BottomEnd:表示子组件位于底部尾端
Stack容器(由Stack组件创建的容器)内子组件的对齐方式,如下图所示:

案例代码如下:
js
@Entry
@Component
struct StackTest {
build() {
Stack({ alignContent: Alignment.Bottom }) {
Text('First child, show in bottom')
.width('90%')
.height('100%')
.backgroundColor('#fffde5ad')
.align(Alignment.Top)
Text('Second child, show in top')
.width('70%')
.height('60%')
.backgroundColor('#ff8fffcc')
.align(Alignment.BottomEnd)
.textAlign(TextAlign.End)
}
.width('100%')
.height(150)
.margin({ top: 5 })
}
}
页面效果图如下:

6. 双向数据绑定
双向数据绑定 是一种将组件的状态与变量的值自动同步的机制:
- 组件状态变化时会自动更新变量的值
- 变量的值变化时会自动更新组件状态
这种机制简化了数据管理和UI更新的过程
为了实现双向数据绑定,需要先定义状态变量,语法格式如下:
js
@State 变量名: 类型 = 值;
其实就是在变量前面加上【@State】修饰符即可
双向数据绑定的方式分为绑定参数和绑定属性,不同组件支持不同的双向数据绑定方式,有的可能只支持绑定参数,有的可能只支持绑定属性,有的则可能两者都支持,具体情况可参考鸿蒙开发文档
绑定参数的语法格式如下:
js
组件名({ 参数名: $$this.变量名 })
绑定属性的语法格式如下:
js
组件名()
.属性名($$this.变量名)
7. 循环渲染语句
循环渲染语句主要是通过ForEach()函数实现的- 使用ForEach()函数可以
基于数组进行循环渲染,在渲染过程中,系统会为每个数组元素生成一个唯一且持久的键,用于标识对应的组件 - 当这个
键发生变化时,ArkUI将视为该数组元素已被替换或修改,并会基于新的键创建一个新的组件
ForEach()函数的语法格式如下:
js
ForEach(
arr: Array,
itemGenerator: (item: 类型, index?: number) => void,
keyGenerator?: (item: 类型, index?: number): string => string
)
- 参数arr表示数据源,它是一个数组
- 参数itemGenerator表示组件生成函数
- 参数keyGenerator表示键生成函数
在这两个函数中,item参数 表示数组 中元素的值,index参数 表示数组 中元素的索引
itemGenerator表示的函数会为数组中的每个元素创建组件,该函数中可以包含条件渲染语句,也可以在条件渲染语句中使用ForEach()函数
在keyGenerator表示的函数中可以自定义键的生成规则。如果开发者没有定义keyGenerator表示的函数,则ArkUI会使用默认的键生成函数,相当于如下代码:
js
(item: 类型, index: number) => index + '__' + JSON.stringify(item);
8. 组件代码复用
1. @Styles
@Styles装饰器用于装饰一个方法
在被@Styles装饰器装饰的方法中可以编写多条通用属性 和通用事件 的代码,通过组件调用该方法即可复用该方法中的代码
定义方法时,可以在struct外使用@Styles装饰器定义或在struct内使用@Styles装饰器定义
- 如果在struct外使用@Styles装饰器定义,该方法可以在同一文件的所有struct中使用
- 如果在struct内使用@Styles装饰器定义,则该方法只能在相应的struct中使用
在struct外使用@Styles装饰器定义方法的语法格式如下:
js
@Styles
function 方法名() {}
在struct内使用@Styles装饰器定义方法的语法格式如下:
js
@Styles
方法名() {}
注意:在struct内使用@Styles装饰器定义的方法中的代码具有更高的优先级,会覆盖在struct外使用@Styles装饰器定义的方法中的代码。另外,这两个方法都不允许传递参数
案例代码如下:
js
@Entry
@Component
struct Index {
@State msg: string = '华为-鸿蒙'
build() {
Column() {
Text(this.msg)
.backgroundColor("#0A59F7")
.borderRadius(5)
.borderStyle(BorderStyle.Dotted)
.borderWidth(2)
.borderColor(Color.Red)
.width(100)
.fontSize(14)
.fontColor(Color.White)
//stateStyles:设置组件不同状态的样式
.stateStyles({
//pressed:组件按下状态的样式
pressed: pressedStyles,
})
.padding(12)
.textAlign(TextAlign.Center)
}
.width('100%')
.height('100%')
}
}
@Styles
function pressedStyles() {
.backgroundColor("#ED6F21")
.borderRadius(10)
.borderStyle(BorderStyle.Dashed)
.borderWidth(2)
.borderColor("#33000000")
.width(120)
.opacity(1)
}
或者讲【pressedStyles】放在struct内部,代码如下:
js
@Entry
@Component
struct Index {
@State msg: string = '华为-鸿蒙'
@Styles
pressedStyles() {
.backgroundColor("#ED6F21")
.borderRadius(10)
.borderStyle(BorderStyle.Dashed)
.borderWidth(2)
.borderColor("#33000000")
.width(120)
.opacity(1)
}
build() {
Column() {
Text(this.msg)
.backgroundColor("#0A59F7")
.borderRadius(5)
.borderStyle(BorderStyle.Dotted)
.borderWidth(2)
.borderColor(Color.Red)
.width(100)
.fontSize(14)
.fontColor(Color.White)
//stateStyles:设置组件不同状态的样式
.stateStyles({
//pressed:组件按下状态的样式
pressed: this.pressedStyles,
})
.padding(12)
.textAlign(TextAlign.Center)
}
.width('100%')
.height('100%')
}
}
页面效果是一致的,如下图所示:

点击时样式变成这样了:

2. @Extend
@Extend装饰器与@Styles装饰器功能类似,区别在于:
@Extend装饰器支持组件的私有属性和私有事件的代码,允许传递参数- 它仅支持 在
struct外定义方法,该方法可以在同一文件的所有struct中使用
在struct外使用@Extend装饰器定义方法的语法格式如下:
js
@Extend(组件名)
function 方法名(参数1: 类型, 参数2: 类型, ...) {}
在上述语法格式中,参数的数量可以是0个或多个
调用方法的语法格式如下:
js
组件名()
.方法名(参数1, 参数2, ...)
在上述语法格式中,参数要与方法定义时的参数一致
案例代码如下:
js
@Entry
@Component
struct Index {
build() {
Column() {
TextInput({ placeholder: '请填写收货人手机号' })
.maxLength(11) // 设置文本的最大输入字符数
.myInputStyle()
}
.width('100%')
.height('100%')
}
}
// TextInput组件的自定义样式扩展
@Extend(TextInput)
function myInputStyle() {
.placeholderColor('#99000000') // 占位符颜色
.height('40') // 输入框高度
.backgroundColor('#fff18989') // 背景颜色
.width('78%') // 宽度为父组件的100%
.padding({ left: 10 }) // 左侧填充
.borderRadius(10)
}
页面效果如下图所示:

3. @Builder
1. 使用说明
@Builder装饰器 用于装饰一个函数,被装饰的函数被称为自定义构建函数,用于定义组件的声明式UI结构,以便复用这些UI结构
在定义自定义构建函数时,可以在struct外使用@Builder装饰器定义或在struct内使用@Builder装饰器定义
- 如果在struct外使用@Builder装饰器定义,该自定义构建函数可以在同一文件的所有struct中使用
- 如果在struct内使用@Builder装饰器定义,则该自定义构建函数只能在相应的struct中使用
在struct外使用@Builder装饰器定义自定义构建函数的语法格式如下:
js
@Builder
function 函数名(参数1: 类型, 参数2: 类型, ...) {}
调用自定义构建函数的语法格式如下:
js
函数名(参数1, 参数2, ...)
在struct内使用@Builder装饰器定义自定义构建函数的语法格式如下:
js
@Builder
函数名(参数1: 类型, 参数2: 类型, ...) {}
调用自定义构建函数的语法格式如下:
js
this.函数名(参数1, 参数2, ...)
this表示当前所属组件的对象
1. 私有自定义构建函数
js
@Entry
@Component
struct BuilderDemo {
@Builder
showTextBuilder() {
// @Builder装饰此函数,使其能以链式调用的方式配置并构建Text组件
Text('Hello World')
.fontSize(30)
.fontWeight(FontWeight.Bold)
}
@Builder
showTextValueBuilder(param: string) {
Text(param)
.fontSize(30)
.fontWeight(FontWeight.Bold)
}
build() {
Column() {
// 无参数
this.showTextBuilder()
// 有参数
this.showTextValueBuilder('Hello @Builder')
}
}
}
使用方法:
- 允许在自定义组件内定义一个或多个@Builder函数,该函数被认为是该组件的私有、特殊类型的成员函数。
- 私有自定义构建函数允许在自定义组件内、build函数和其他自定义构建函数中调用。
- 在自定义组件中,this指代当前所属组件,组件的状态变量可在自定义构建函数内访问。建议通过this访问组件的状态变量,而不是通过参数传递。
2. 全局自定义构建函数
js
@Builder
function showTextBuilder() {
Text('Hello World')
.fontSize(30)
.fontWeight(FontWeight.Bold)
}
@Entry
@Component
struct BuilderDemo {
build() {
Column() {
showTextBuilder()
}
}
}
- 如果不涉及组件状态变化,建议使用全局的自定义构建函数。
- 全局自定义构建函数允许在build函数和其他自定义构建函数中调用。
2. 参数传递规则
自定义构建函数的参数传递有按值传递和按引用传递两种,均需遵守以下规则:
- 参数的类型必须与参数声明的类型一致,不允许undefined、null和返回undefined、null的表达式。
- 在@Builder装饰的函数内部,不允许改变参数值。
- @Builder内UI语法遵循
UI语法规则 - 只有当传入一个参数且该参数直接传入对象字面量时,才会按引用传递,其他传递方式均为按值传递。
1. 按值传递
调用@Builder装饰的函数默认按值传递。当传递的参数为状态变量时,状态变量的改变不会引起@Builder函数内的UI刷新。所以当使用状态变量的时候,推荐使用按引用传递
js
class ObjectParamClass {
firstValue: string = '';
secondValue: string = '';
}
@Entry
@Component
struct Parent {
@State m1: string = 'Hello World'
@Builder
MyRow(msg: string) {
Column() {
Text(msg)
.fontSize(30)
}
}
build() {
Column() {
this.MyRow(this.m1)
Button('改变').onClick(() => {
// 单击[改变]按钮后,UI文本无法从Hello World更改为Good ArkUI
this.m1 = 'Good ArkUI';
})
}
.width('100%')
.height('100%')
}
}
2. 按引用传递
按引用传递参数时,传递的参数可为状态变量 ,且状态变量的改变会引起@Builder函数内的UI刷新
js
class ObjectParamClass {
firstValue: string = '';
secondValue: string = '';
}
@Entry
@Component
struct Parent {
@State m1: string = 'Hello'
@State m2: string = 'World'
@Builder
MyRow(params: ObjectParamClass) {
Column() {
Text(params.firstValue + ' ' + params.secondValue)
.fontSize(30)
}
}
build() {
Column() {
this.MyRow({ firstValue: this.m1, secondValue: this.m2 })
Button('改变').onClick(() => {
// 单击[改变]按钮后,UI文本从Hello World更改为Good ArkUI
this.m1 = 'Good';
this.m2 = 'ArkUI';
})
}
.width('100%')
.height('100%')
}
}
9. Tabs组件
官网介绍地址:
https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-tabs
Tabs 通过页签进行内容视图切换的容器组件,每个页签对应一个内容视图。
1. 初使用
根据官网代码,我们先写一个测试页面如下:

代码如下:
js
@Entry
@Component
struct Demo01 {
@State fontColor: string = '#182431';
@State selectedFontColor: string = '#007DFF';
@State currentIndex: number = 0;
@State selectedIndex: number = 0;
private controller: TabsController = new TabsController();
@Builder
tabBuilder(index: number, name: string) {
Column({ space: 8 }) {
Text(name)
.fontColor(this.selectedIndex === index ? this.selectedFontColor : this.fontColor)
.fontSize(16)
.fontWeight(this.selectedIndex === index ? 500 : 400)
.lineHeight(22)
Divider()
.strokeWidth(2)
.color('#007DFF')
.opacity(this.selectedIndex === index ? 1 : 0)
.width(30)
}.width('100%')
}
build() {
Column() {
Tabs({ barPosition: BarPosition.End, index: this.currentIndex, controller: this.controller }) {
TabContent() {
Column().width('100%').height('100%').backgroundColor('#00CB87')
}.tabBar(this.tabBuilder(0, '首页'))
TabContent() {
Column().width('100%').height('100%').backgroundColor('#007DFF')
}.tabBar(this.tabBuilder(1, '广场'))
TabContent() {
Column().width('100%').height('100%').backgroundColor('#FFBF00')
}.tabBar(this.tabBuilder(2, '消息'))
TabContent() {
Column().width('100%').height('100%').backgroundColor('#E67C92')
}.tabBar(this.tabBuilder(3, '我的'))
}
.vertical(false)
.barMode(BarMode.Fixed)
.barWidth(360)
.barHeight(56)
.animationDuration(400)
.onChange((index: number) => {
// currentIndex控制TabContent显示页签
this.currentIndex = index;
this.selectedIndex = index;
})
.onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
if (index === targetIndex) {
return;
}
// selectedIndex控制自定义TabBar内Image和Text颜色切换
this.selectedIndex = targetIndex;
})
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
.width('100%')
.height('100%')
}
}
2. 优化版
如果我们需要底部菜单显示图片的话,就需要修改下代码了,效果图如下:

代码如下:
js
@Entry
@Component
struct Demo01 {
@State fontColor: string = '#182431';
@State selectedFontColor: string = '#007DFF';
@State currentIndex: number = 0;
@State selectedIndex: number = 0;
private controller: TabsController = new TabsController();
@Builder
tabBuilder(index: number, name: string, img: ResourceStr) {
Column({ space: 3 }) {
Image(img)
.width(28)
.fillColor(this.selectedIndex === index ? this.selectedFontColor : this.fontColor)
Text(name)
.fontColor(this.selectedIndex === index ? this.selectedFontColor : this.fontColor)
.fontSize(this.selectedIndex === index ? 18 : 16)
.fontWeight(this.selectedIndex === index ? 500 : 400)
}.width('100%')
.padding({ top: 4 })
}
build() {
Column() {
Tabs({ barPosition: BarPosition.End, index: this.currentIndex, controller: this.controller }) {
TabContent() {
Column().width('100%').height('100%').backgroundColor('#00CB87')
}.tabBar(this.tabBuilder(0, '首页', $r('app.media.m1')))
TabContent() {
Column().width('100%').height('100%').backgroundColor('#007DFF')
}.tabBar(this.tabBuilder(1, '广场', $r('app.media.m2')))
TabContent() {
Column().width('100%').height('100%').backgroundColor('#FFBF00')
}.tabBar(this.tabBuilder(2, '消息', $r('app.media.m3')))
TabContent() {
Column().width('100%').height('100%').backgroundColor('#E67C92')
}.tabBar(this.tabBuilder(3, '我的', $r('app.media.m4')))
}
.vertical(false)
.barMode(BarMode.Fixed)
.barWidth(360)
.barHeight(56)
.animationDuration(400)
.onChange((index: number) => {
// currentIndex控制TabContent显示页签
this.currentIndex = index;
this.selectedIndex = index;
})
.onAnimationStart((index: number, targetIndex: number, event: TabsAnimationEvent) => {
if (index === targetIndex) {
return;
}
// selectedIndex控制自定义TabBar内Image和Text颜色切换
this.selectedIndex = targetIndex;
})
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
.width('100%')
.height('100%')
}
}
3. 小作业
实现下面两个页面:
