第一部分:布局系列(共 6 篇)


博客 1:鸿蒙 Column 垂直布局超全详解|对齐、权重、嵌套、避坑实战
一、前言
在 HarmonyOS ArkTS 开发中,Column 是最基础、使用频率最高的垂直布局容器,所有子组件会按照从上到下的顺序垂直排列,页面绝大多数表单、长列表、登录页、详情页都会以 Column 作为根布局。本文完整讲解 Column 属性、权重分配、嵌套规则、实战案例与常见踩坑。
二、Column 基础特性
排布规则:子组件垂直纵向依次摆放;
主轴:垂直方向(上下);交叉轴:水平方向(左右);
必须作为父容器包裹其他组件,支持嵌套任意布局、组件。
三、核心常用属性
1. 主轴对齐 justifyContent(垂直方向控制)
FlexAlign.Start:顶部对齐(默认)
FlexAlign.Center:垂直居中
FlexAlign.End:底部对齐
FlexAlign.SpaceBetween:上下贴边,中间元素均分空隙
FlexAlign.SpaceAround:每个元素上下均匀留白
FlexAlign.SpaceEvenly:所有间隙完全相等
2. 交叉轴对齐 alignItems(水平方向控制)
ItemAlign.Start:左对齐
ItemAlign.Center:水平居中(最常用)
ItemAlign.End:右对齐
ItemAlign.Stretch:子组件宽度拉伸填满父容器
3. 间距与内边距
space(number):子组件之间统一垂直间距
padding():容器内边距,支持上下左右单独设置
margin():容器外边距,与外部元素拉开距离
4. layoutWeight 自适应权重(核心重点)
给子组件设置layoutWeight(1),代表自动瓜分父容器剩余垂直高度;多个组件设置权重会按比例分配高度。
注意:使用权重时,父 Column 不能设置固定高度,或者父高度有明确约束。
四、完整示例代码
ets
@Entry
@Component
struct ColumnDemo {
  build() {
    Column() {
      Text("顶部标题").fontSize(24).fontWeight(FontWeight.Bold)
      
      // 权重1,自动占满中间剩余高度
      Text("内容区域")
        .layoutWeight(1)
        .width("100%")
        .backgroundColor("#f5f5f5")
      
      Button("底部按钮").width("90%")
    }
    .width("100%")
    .height("100%")
    .justifyContent(FlexAlign.SpaceBetween)
    .alignItems(ItemAlign.Center)
    .space(20)
    .padding(20)
  }
}
五、嵌套实战
Column 内部可以嵌套 Row、Stack、Flex、RelativeLayout,实现复杂复合页面,例如:垂直大框架内部横向放一行标签。
ets
Column() {
  Text("用户信息")
  Row() {
    Text("姓名:")
    TextInput()
  }
}
六、高频踩坑总结
layoutWeight 不生效:父布局未设置固定宽高,或子组件同时写了固定高度;
内容超出屏幕:未使用滚动容器 Scroll 嵌套 Column,长内容会被截断;
多层嵌套卡顿:页面层级不要超过 5 层,优先简化布局结构。
七、适用场景
登录注册页、商品详情、表单页面、设置页、长图文页面。

博客 2:ArkTS Row 水平布局完整教程|导航栏、按钮组、横向列表实战
一、简介
Row 是水平布局容器,子组件从左至右横向排列,是页面导航、按钮行、标签栏、左右图文组合的核心布局。Column 负责纵向,Row 负责横向,两者搭配覆盖 80% 常规页面。
二、核心属性解析
1. 主轴 justifyContent(水平方向)
控制横向子组件排布:居左、居中、两端对齐、均分间距。
2. 交叉轴 alignItems(垂直方向)
控制子组件上下对齐,常用ItemAlign.Center实现垂直居中。
3. layoutWeight 横向权重
子组件设置权重,自动平分父容器剩余宽度,常用于均分 Tab、输入框 + 按钮组合。
4. flexWrap 自动换行
默认子组件不会换行,超出宽度会挤压;设置FlexWrap.Wrap开启自动换行,类似 Flex 弹性布局。
5. gap /space 横向间距
space 统一设置子组件横向间隔,gap 同时控制横竖间隙。
三、基础示例:顶部导航栏
ets
Row() {
  Image($r("sys.media.ohos_ic_public_back")).width(24)
  Text("商品详情").layoutWeight(1).textAlign(TextAlign.Center)
  Image($r("sys.media.ohos_ic_public_share")).width(24)
}
.width("100%")
.padding(15)
.alignItems(ItemAlign.Center)
四、换行流式布局案例
ets
Row() {
  ForEach([1,2,3,4,5,6], item=>{
    Text(`标签${item}`)
      .padding(8)
      .backgroundColor("#eee")
      .borderRadius(6)
  })
}
.width("100%")
.flexWrap(FlexWrap.Wrap)
.gap(10)
五、Row 与 Column 组合规范
绝大多数页面标准结构:根布局 Column,内部多处嵌套 Row,纵向分模块,模块内部横向摆放元素。
六、常见问题
组件挤压变形:开启 flexWrap 自动换行,或使用 layoutWeight 分配宽度;
文字上下不对齐:统一设置alignItems(ItemAlign.Center);
宽度撑不满父容器:给 Row 添加.width("100%")。
七、适用场景
顶部导航、底部按钮组、图文左右排版、标签流式列表、表单单行输入项。

博客 3:ArkTS RelativeLayout 相对布局|自由定位组件,解决复杂参照布局
一、什么是相对布局
Column、Row 只能简单横竖排列,而 RelativeLayout 支持组件互相参照定位:A 组件放在 B 上方 / 下方 / 左侧 / 右侧,也可以相对于父容器居左、居中、居底,适合不规则自由布局场景。
二、核心约束属性
alignParentLeft:贴父容器左侧
alignParentRight:贴父容器右侧
alignParentTop:贴父容器顶部
alignParentBottom:贴父容器底部
alignParentCenter:相对于父容器完全居中
above(id):放置在指定 id 组件上方
below(id):放置在指定 id 组件下方
leftOf(id):放置在指定 id 组件左侧
rightOf(id):放置在指定 id 组件右侧
三、基础代码示例
ets
RelativeLayout() {
  Text("标题")
    .id("title")
    .alignParentTop(true)
    .margin({top:20})
  
  Button("删除")
    .alignParentRight(true)
    .below("title")
    .margin({top:10, right:20})
}
.width("100%")
.height("100%")
四、RelativeLayout vs Stack 层叠布局区别
RelativeLayout:组件互相参照摆放,无层级覆盖,侧重平面定位;
Stack:组件上下堆叠覆盖,后写元素层级更高,侧重浮层、遮罩。
五、适配注意事项
相对布局依赖 id 绑定组件,id 不能重复;多屏幕适配时尽量使用 margin 而非固定坐标,避免小屏错位。
六、适用场景
个人中心头像 + 悬浮按钮、卡片内浮动操作按钮、不规则图文排版。


博客 4:ArkTS Stack 层叠布局|浮层、遮罩、水印、悬浮按钮完整实战
一、Stack 核心原理
Stack 是层叠容器,子组件按代码顺序从上到下堆叠渲染,后声明的组件层级更高,会覆盖前面的组件,是实现遮罩、水印、悬浮按钮、弹窗底层容器的首选布局。
二、关键属性
alignContent:统一设置所有子组件对齐位置(居中、居底、居顶);
zIndex(number):手动控制组件层级,数值越大越靠上;
clip(true):裁剪超出容器范围的内容;
layoutWeight:配合父布局实现自适应大小。
三、实战 1:图片加水印
ets
Stack() {
  Image($r("app.media.img"))
    .width("100%")
    .height(200)
    .objectFit(ImageFit.Cover)
  Text("官方水印")
    .fontSize(14)
    .fontColor("#ffffff88")
    .margin({bottom:10, right:10})
}
.width("100%")
四、实战 2:页面右下角悬浮按钮
ets
Stack() {
  Column() {
    // 页面主体内容
  }
  Button("+")
    .width(50)
    .height(50)
    .borderRadius(25)
    .margin({right:20, bottom:20})
}
.width("100%")
.height("100%")
.alignContent(Alignment.BottomEnd)
五、弹窗底层遮罩实现
弹窗背景半透明黑色遮罩,使用 Stack 底层放遮罩,上层放弹窗内容:
ets
Stack() {
  // 遮罩层
  Rect().width("100%").height("100%").fill("#00000066")
  // 弹窗卡片
  Column(){}.width("80%").height(300").backgroundColor("#fff").borderRadius(12)
}
六、踩坑点
悬浮按钮被内容遮挡:调高 zIndex;
图片溢出容器:添加 clip (true) 裁剪;
层级混乱:严格按 “底层先写,浮层后写” 顺序编码。
七、适用场景
轮播遮罩、水印、悬浮按钮、弹窗、新手引导浮层、头像右上角红点角标。


博客 5:ArkTS Flex 弹性布局|流式多列卡片、自适应标签完整指南
一、Flex 布局定位
Flex 是 Row/Column 的增强版,同时支持主轴切换、自动换行、元素弹性伸缩,专门用于多列网格、自动换行标签、自适应流式列表,弥补 Row 无法自动换行的短板。
二、核心属性
direction(FlexDirection) 主轴方向
Row:横向(默认)
Column:纵向
flexWrap(FlexWrap.Wrap):开启自动换行
gap():行列统一间距
flexGrow:元素自动放大占剩余空间
flexShrink:空间不足时自动缩小
flexBasis:元素基础尺寸
三、多列商品卡片示例(2 列自适应)
ets
Flex({ wrap: FlexWrap.Wrap }) {
  ForEach([1,2,3,4,5,6], item=>{
    Column() {
      Image($r("app.media.goods")).width("100%").height(120)
      Text(`商品${item}`).padding(5)
    }
    .width("48%")
    .marginBottom(10)
  })
}
.width("100%")
.justifyContent(FlexAlign.SpaceBetween)
四、流式标签自动换行
ets
Flex({wrap:FlexWrap.Wrap}) {
  ForEach(["手机","电脑","平板","耳机","手表","音箱"], tag=>{
    Text(tag)
      .padding({x:12,y:6})
      .backgroundColor("#e8f3ff")
      .borderRadius(20)
  })
}
.gap(8)
.width("100%")
五、Flex 和 Row/Column 选择标准
简单单行 / 单列、不需要换行:用 Row/Column,性能更好;
需要自动换行、多列网格、弹性伸缩:用 Flex。
六、适配优化
多设备屏幕宽度变化时,Flex 会自动重新换行,无需手动计算宽度,适配性远优于固定 Row 布局。
七、适用场景
商品网格列表、搜索标签、相册图片流式布局、分类多宫格。


博客 6:ArkTS 布局硬性规范:页面只能存在一个根布局,嵌套最佳实践
一、核心规则
HarmonyOS ArkTS 页面有强制语法规范:单个 @Entry 页面 build 方法内,顶层只能有且仅有一个根布局容器(Column/Row/Stack/Flex/RelativeLayout 任意一种),不允许并列多个根容器。
错误写法(直接编译报错)
ets
@Entry
@Component
struct ErrorPage {
  build() {
    // 两个并列根布局,非法!
    Column(){}
    Row(){}
  }
}
标准正确写法
使用单一根布局包裹全部内容,内部再嵌套其他布局:
ets
@Entry
@Component
struct RightPage {
  build() {
    // 唯一根布局Column
    Column() {
      Row(){} // 内部嵌套水平布局
      Stack(){} // 内部嵌套层叠布局
      Flex(){} // 内部嵌套弹性布局
    }
  }
}
二、嵌套逻辑详解
根布局:页面最外层唯一容器;
子布局:根布局内部可无限嵌套 Row、Column、Stack、Flex、RelativeLayout,无数量限制;
嵌套层级建议:最多 3~5 层,层级过深会降低页面渲染性能。
三、多模块页面标准结构模板
ets
Column() { // 唯一根布局
  // 1.顶部导航 Row
  Row(){}

  // 2.轮播 Stack
  Stack(){}

  // 3.商品列表 Flex
  Flex({wrap:FlexWrap.Wrap}){}

  // 4.底部按钮 Row
  Row(){}
}
.width("100%")
.height("100%")
四、多层嵌套性能优化方案
能一层实现绝不嵌套两层;
优先使用 layoutWeight、对齐属性替代多层包裹;
长列表使用 List 组件,不要用多层 Flex/Column 循环渲染。
五、常见新手误区
页面写多个并列 Column/Row,报语法错误;
无意义多层嵌套,页面滑动卡顿;
根布局忘记设置宽高 100%,页面内容无法铺满全屏。
六、总结
所有页面遵循「单一根布局 + 内部自由嵌套」规范,是鸿蒙 UI 开发基础硬性要求,也是页面布局性能优化的起点。

第二部分:组件系列(共 9 篇)


博客 7:ArkTS Swiper 轮播图完整开发|自动轮播、指示器、切换监听实战
一、Swiper 组件介绍
Swiper 是鸿蒙官方轮播容器,用于首页 Banner 广告、图片轮播、多页面滑动切换,支持自动播放、手势滑动、自定义指示器、切换事件监听。
二、核心属性
index:绑定当前轮播索引,配合 @State 状态管理;
autoPlay(true):开启自动轮播;
interval(3000):自动切换间隔毫秒;
loop(true):循环轮播,首尾无缝衔接;
indicator():内置指示器配置,支持颜色、尺寸;
onChange((index)=>{}):监听滑动切换,返回当前索引。
三、完整轮播代码示例
ets
@Entry
@Component
struct SwiperDemo {
  @State curIndex: number = 0
  bannerList: ResourceColor[] = [$r("app.media.b1"),$r("app.media.b2"),$r("app.media.b3")]

  build() {
    Column() {
      Swiper() {
        ForEach(this.bannerList, item=>{
          Image(item)
            .width("100%")
            .height(180)
            .objectFit(ImageFit.Cover)
            .borderRadius(10)
        })
      }
      .index(this.curIndex)
      .autoPlay(true)
      .interval(3000)
      .loop(true)
      .indicator(
        Indicator()
          .selectedColor("#007dff")
          .unselectedColor("#ffffff88")
          .itemWidth(8)
          .itemHeight(8)
      )
      .onChange((idx:number)=>{
        this.curIndex = idx
        console.info("当前轮播索引:", idx)
      })
      .width("100%")
      .height(180)
    }
    .padding(15)
  }
}
四、高级拓展
关闭手势滑动:disableSwipe(true);
自定义指示器(不使用内置,自己写小圆点);
轮播混合视频 + 图片;
轮播点击跳转页面(给 Image 绑定 onClick 路由)。
五、踩坑总结
autoPlay 失效:loop 未开启、Swiper 高度为 0;
指示器不显示:Swiper 高度不足;
索引不同步:未使用 @State 绑定 index。
六、适用场景
首页广告 Banner、活动宣传图、相册滑动预览、多图商品展示。


博客 8:ArkTS Video 视频组件|本地 / 网络视频播放、进度、全屏控制
一、Video 组件作用
官方视频播放组件,支持本地资源视频、网络在线视频,自带播放控制器,可监听播放进度、缓冲、播放完成事件,实现短视频、课程播放页面。
二、核心属性
src:视频资源地址(本地 $r 或网络 url);
controls(true):显示系统播放控制栏;
autoPlay:进入页面自动播放;
muted:静音播放;
objectFit:视频画面缩放适配;
onStart:开始播放回调;
onFinish:播放完成回调;
onUpdate:实时进度回调。
三、基础播放代码
ets
Video({src: $r("app.media.test_video")})
  .width("100%")
  .height(220)
  .controls(true)
  .autoPlay(false)
  .onFinish(()=>{
    console.info("视频播放完毕")
  })
  .onUpdate((time)=>{
    console.info("当前播放时间:", time.currentTime)
  })
四、网络视频配置注意
播放网络视频需要在module.json5中配置网络权限:
json
"requestPermissions": [
  {"name": "ohos.permission.INTERNET"}
]
五、自定义播放器拓展
隐藏原生 controls,自行封装播放 / 暂停按钮、进度条、全屏切换,结合 Stack 布局叠加控制层。
六、适用场景
短视频页面、课程视频、商品宣传视频、本地视频预览。


博客 9:ArkTS Image 图片组件全解|网络图、缩放、圆角、滤镜、缓存优化
一、Image 加载资源三种方式
本地图片:$r("app.media.xxx");
网络图片:直接传入 url 字符串;
像素图:PixelMap(动态生成图片)。
二、核心属性
objectFit 缩放模式
Cover:铺满容器,裁剪多余部分(商品图常用)
Contain:完整显示图片,留白
Fill:拉伸填满,会变形
borderRadius:圆角、圆形头像;
fillOpacity:透明度;
filter:灰度、模糊滤镜;
alt:图片加载失败占位图。
三、圆形头像示例
ets
Image($r("app.media.avatar"))
  .width(80)
  .height(80)
  .borderRadius(40)
  .objectFit(ImageFit.Cover)
四、网络图片加载
ets
Image("https://xxx.com/xxx.jpg")
  .width("100%")
  .height(150)
  .alt($r("app.media.default_img")) // 加载失败占位图
五、性能优化
图片尺寸和显示宽高匹配,避免大图缩放浪费性能;
列表图片统一使用合适压缩尺寸;
网络图片提前配置缓存策略。
六、常见问题
网络图片空白:未开启网络权限;
头像圆角失效:忘记设置 objectFit,图片拉伸溢出;
图片模糊:原图分辨率过低。
七、适用场景
头像、商品图、Banner、图标、背景图、页面装饰图片。


博客 10:ArkTS Tabs 选项卡|底部导航、顶部分类 Tab 完整封装
一、Tabs 组件结构
Tabs = 容器 + TabContent 页面内容,一套组件实现多页面切换,分为顶部 Tab 分类、底部 App 导航两种主流样式。
二、核心 API
index:绑定当前选中标签索引;
barWidth/barHeight:Tab 栏尺寸;
barMode:固定宽度 / 自适应宽度;
onChange((idx)=>{}):切换标签回调;
TabContent:每个标签对应独立页面。
三、底部导航完整示例
ets
@Entry
@Component
struct TabDemo {
  @State tabIndex: number = 0
  tabList: {title:string, icon:Resource}[] = [
    {title:"首页", icon:$r("sys.media.ohos_ic_public_home")},
    {title:"分类", icon:$r("sys.media.ohos_ic_public_list")},
    {title:"我的", icon:$r("sys.media.ohos_ic_public_user")}
  ]

  build() {
    Tabs() {
      TabContent() { Text("首页页面") }
        .tabBar(this.buildTabItem(0))
      TabContent() { Text("分类页面") }
        .tabBar(this.buildTabItem(1))
      TabContent() { Text("个人中心") }
        .tabBar(this.buildTabItem(2))
    }
    .index(this.tabIndex)
    .vertical(false)
    .barHeight(60)
    .onChange((idx)=>{
      this.tabIndex = idx
    })
  }

  @Builder buildTabItem(idx:number) {
    Column() {
      Image(this.tabList[idx].icon).width(24)
      Text(this.tabList[idx].title)
        .fontSize(12)
        .fontColor(this.tabIndex === idx ? "#007dff" : "#666")
    }
    .width("100%")
    .justifyContent(FlexAlign.Center)
  }
}
四、顶部分类 Tab 设置
设置vertical(false),barHeight 调小,放在页面顶部实现商品分类切换。
五、联动路由拓展
切换 Tab 时使用 router 跳转对应页面,实现多页面路由隔离。
六、踩坑点
Tab 切换页面状态丢失:使用 @State 持久化数据;
Tab 文字不居中:tabBar 内部布局设置居中对齐。
七、适用场景
App 底部主导航、商品顶部分类、资讯标签切换。


博客 11:ArkTS Text 文本组件|字体、行间距、富文本、文字省略全技巧
一、Text 基础文本组件
页面所有文字展示统一使用 Text,支持基础样式、超长文本截断、富文本、渐变文字、点击交互。
二、核心样式属性
fontSize:字号;
fontWeight:字重(Normal/Bold/Lighter);
fontColor:文字颜色;
lineHeight:行高;
letterSpacing:字间距;
maxLines:最大显示行数;
textOverflow:超长省略(Ellipsis 省略号);
textAlign:对齐方式(左 / 中 / 右)。
三、超长文本省略示例
ets
Text("超长商品描述文本,超出两行自动显示省略号")
  .maxLines(2)
  .textOverflow({overflow: TextOverflow.Ellipsis})
  .fontSize(14)
  .fontColor("#333")
四、富文本 RichText
加载 HTML 富文本内容,展示带格式图文:
ets
RichText("<p style='color:red'>红色富文本内容</p>")
五、可点击文字
Text 直接绑定 onClick 实现文字按钮:
ets
Text("忘记密码?")
  .fontColor("#007dff")
  .onClick(()=>{
    // 跳转找回密码页面
  })
六、进阶效果:渐变文字
结合线性渐变背景实现彩色文字。
七、适用场景
标题、正文、提示文字、链接文字、标签文本。


博客 12:ArkTS TextInput 输入框|表单、密码、实时输入校验 onChange 实战
一、TextInput 表单核心组件
登录、搜索、评论页面必备,支持文本、数字、密码输入,实时监听输入内容,限制输入长度。
二、核心属性
@State双向绑定文本值;
placeholder:输入提示文字;
type:输入类型(Normal/Password/Number/Email);
maxLength:最大输入字符;
onChange((value)=>{}):实时监听输入内容;
onSubmit:回车确认回调;
caretColor:光标颜色。
三、登录账号密码完整示例
ets
@Entry
@Component
struct InputDemo {
  @State account: string = ""
  @State pwd: string = ""

  build() {
    Column() {
      TextInput({text: this.account, placeholder:"请输入账号"})
        .type(InputType.Normal)
        .maxLength(11)
        .onChange((val:string)=>{
          this.account = val
        })
      
      TextInput({text: this.pwd, placeholder:"请输入密码"})
        .type(InputType.Password)
        .onChange((val:string)=>{
          this.pwd = val
        })
    }
    .space(15)
    .padding(20)
  }
}
四、实时输入校验
在 onChange 中判断输入长度、正则校验手机号 / 邮箱,实时提示错误。
五、样式美化
设置圆角、边框、焦点变色、内边距,美化输入框表单。
六、踩坑
输入值不更新:忘记在 onChange 给 State 变量赋值;
密码明文显示:type 未设置 Password;
输入超出长度:未配置 maxLength。
七、适用场景
登录注册表单、搜索框、评论输入、资料编辑页。


博客 13:ArkTS Button 按钮组件|填充、线条、文字按钮、点击事件 onClick
一、Button 三种基础类型
Normal:填充背景按钮(默认);
Outline:描边线条按钮;
NormalText:纯文字无背景按钮。
二、核心属性
type:按钮类型;
stateEffect(true):开启按压变色效果;
disabled:禁用不可点击;
onClick(()=>{}):点击事件回调;
自定义背景渐变、圆角、阴影。
三、三种按钮代码示例
ets
Column() {
  // 填充按钮
  Button("登录", {type:ButtonType.Normal})
    .width("100%")
    .backgroundColor("#007dff")
    .borderRadius(8)
    .onClick(()=>{})

  // 线条按钮
  Button("重置", {type:ButtonType.Outline})
    .width("100%")
    .fontColor("#007dff")

  // 文字按钮
  Button("跳过", {type:ButtonType.NormalText})
    .fontColor("#666")
}
.space(12)
四、图文组合按钮
Button 内部嵌套 Row,放置图标 + 文字,实现带图标按钮。
五、禁用状态
ets
Button("提交")
  .disabled(this.account.length < 6)
六、适用场景
登录提交、弹窗确认、表单重置、页面跳转按钮、操作功能键。


博客 14:ArkTS Radio 单选框组件|分组互斥选择、表单单选 onChange 监听
一、Radio 单选组件规则
Radio 必须配合 RadioGroup 分组,同一分组内多个 Radio 互斥,同一时间只能选中一个,适合性别、单选问卷场景。
二、核心 API
RadioGroup:分组容器,绑定选中值;
Radio:单选选项,设置 value 区分;
onChange((value)=>{}):选中切换回调,返回当前选中 value。
三、性别单选完整示例
ets
@Entry
@Component
struct RadioDemo {
  @State selectVal: string = "male"

  build() {
    Column() {
      Text("请选择性别")
      RadioGroup({group: "genderGroup"}) {
        Row() {
          Radio({value:"male", group:"genderGroup"})
          Text("男")
        }
        Row() {
          Radio({value:"female", group:"genderGroup"})
          Text("女")
        }
      }
      .onChange((val:string)=>{
        this.selectVal = val
        console.info("选中:", val)
      })
    }
    .padding(20)
  }
}
四、自定义单选框样式
隐藏原生 Radio,使用 Image 切换选中 / 未选中图标,实现自定义单选 UI。
五、表单取值逻辑
提交表单时直接读取 @State 绑定的 selectVal,获取用户选择项。
六、踩坑
多个 Radio 不互斥:group 名称不一致;
选中值不更新:onChange 未同步赋值 State 变量。
七、适用场景
性别选择、订单支付方式、问卷单选、会员套餐单选。


博客 15:ArkTS Toggle 开关组件|设置页布尔开关、onChange 状态监听
一、Toggle 组件介绍
布尔型开关组件,只有开启 / 关闭两种状态,绑定 @State 布尔变量,常用于设置页面功能开关。
二、核心属性
isOn:绑定开关状态 true 开启 /false 关闭;
onChange((isOpen:boolean)=>{}):切换状态回调;
selectedColor:开启后轨道颜色;
switchPointColor:滑块颜色。
三、消息推送开关示例
ets
@Entry
@Component
struct ToggleDemo {
  @State msgPush: boolean = true

  build() {
    Row() {
      Text("接收消息推送")
      Toggle({isOn: this.msgPush})
        .selectedColor("#007dff")
        .onChange((status:boolean)=>{
          this.msgPush = status
          if(status) {
            console.info("开启推送")
          } else {
            console.info("关闭推送")
          }
        })
    }
    .width("100%")
    .justifyContent(FlexAlign.SpaceBetween)
    .alignItems(ItemAlign.Center)
    .padding(20)
  }
}
四、多开关设置页面组合
Column 嵌套多行 Row+Toggle,实现夜间模式、自动播放、缓存等多项设置。
五、联动逻辑
开关状态改变后,修改页面全局配置、存储本地缓存。
六、适用场景
App 设置页功能开关、隐私授权、自动播放、夜间模式、消息通知。
第三部分:核心语法与 API 知识(共 6 篇)


博客 16:ArkTS @State 装饰器详解|页面响应式状态管理 @status
一、@State 是什么(@status)
@State 是 ArkTS 最基础的页面内响应式装饰器,用来标记组件内部状态变量;当变量值修改时,所有绑定该变量的 UI 组件会自动刷新渲染,也就是双向数据绑定。
二、基础使用规则
仅作用于当前 @Component 自定义组件内部;
支持基础类型:string、number、boolean、数组、简单对象;
变量修改 → 自动刷新页面 UI;
修饰变量必须赋初始值。
三、各类数据绑定示例
1. 布尔值绑定 Toggle 开关
ets
@State isOpen: boolean = false
Toggle({isOn: this.isOpen})
  .onChange(v=>this.isOpen = v)
2. 字符串绑定输入框 TextInput
ets
@State inputText: string = ""
TextInput({text: this.inputText})
  .onChange(v=>this.inputText = v)
3. 数字绑定轮播索引
ets
@State swiperIdx: number = 0
Swiper().index(this.swiperIdx).onChange(idx=>this.swiperIdx=idx)
4. 数组循环渲染列表
ets
@State list: number[] = [1,2,3]
ForEach(this.list, item=>Text(item.toString()))
四、刷新原理
@State 变量被 UI 组件依赖后,底层建立响应式监听;一旦变量赋值操作触发,框架自动执行 build () 重新渲染页面对应组件。
五、高频踩坑
对象修改 UI 不刷新:直接替换对象,不要修改对象内部属性;
ets
// 错误
this.user.name = "张三"
// 正确
this.user = {...this.user, name:"张三"}
忘记初始化 @State 变量,编译报错;
跨组件传值失效:@State 仅当前组件生效,跨组件使用 @Prop/@Link。
六、适用场景
所有页面动态数据:输入内容、开关状态、列表数据、选中索引、弹窗显示隐藏。


博客 17:ArkTS 弹窗开发全方案|Alert 系统弹窗 + CustomDialog 自定义弹窗
一、两种弹窗方案
Alert:系统极简弹窗,无需自定义布局,快速提示、确认框;
CustomDialog:自定义弹窗,支持任意布局、表单、复杂交互。
二、Alert 系统弹窗示例
1. 单按钮提示弹窗
ets
AlertDialog.show({
  message: "操作成功",
  primaryButton: {
    value: "确定",
    action: ()=>{}
  }
})
2. 双按钮确认弹窗(删除二次确认)
ets
AlertDialog.show({
  message: "确定删除该数据吗?删除后无法恢复",
  primaryButton: {value:"取消", action:()=>{}},
  secondaryButton: {
    value:"删除",
    fontColor: "#f53f3f",
    action: ()=>{
      // 执行删除逻辑
    }
  }
})
三、CustomDialog 自定义弹窗完整封装
1. 定义弹窗组件
ets
@CustomDialog
struct LoginDialog {
  controller: CustomDialogController
  @State account: string = ""

  build() {
    Column() {
      Text("登录弹窗").fontSize(20)
      TextInput({text:this.account, placeholder:"输入账号"})
        .onChange(v=>this.account=v)
      Button("确认登录")
        .onClick(()=>{
          this.controller.close()
        })
    }
    .width("85%")
    .padding(20)
    .backgroundColor("#fff")
    .borderRadius(12)
  }
}
2. 页面唤起弹窗
ets
@Entry
@Component
struct DialogPage {
  dialogCtrl: CustomDialogController = new CustomDialogController({
    builder: LoginDialog()
  })

  build() {
    Button("打开登录弹窗")
      .onClick(()=>{
        this.dialogCtrl.open()
      })
  }
}
四、弹窗进阶技巧
遮罩层、点击外部关闭弹窗;
弹窗向父页面回传数据;
弹窗嵌套路由、列表、表单组件。
五、场景选择标准
简单提示、确认:用 Alert,开发速度快;
表单、选择器、复杂布局弹窗:使用 CustomDialog 自定义弹窗。
六、适用场景
操作成功提示、删除确认、登录弹窗、选择城市、商品筛选弹窗。


博客 18:ArkTS 页面路由 Router 完整指南|跳转、传参、返回、路由栈管理
一、Router 路由核心作用
实现页面之间跳转、参数传递、页面栈返回,是多页面 App 页面切换核心 API。
二、基础路由 API
router.pushUrl({url:"pages/xxx/xxx"}):新开页面,保留当前页面进栈;
router.back():返回上一页,销毁当前页面;
router.replaceUrl():替换当前页面,不新增栈;
router.clear():清空全部页面栈,常用于登录成功跳转首页。
三、页面跳转传参
1. 跳转页面携带参数
ets
import router from '@ohos.router'

// 跳转并传递id、名称参数
router.pushUrl({
  url: "pages/detail/detail",
  params: {
    goodsId: 1001,
    goodsName: "手机"
  }
})
2. 目标页面接收参数
ets
import router from '@ohos.router'

@Entry
@Component
struct DetailPage {
  @State id: number = 0
  @State name: string = ""

  aboutToAppear() {
    const params = router.getParams() as {goodsId:number, goodsName:string}
    this.id = params.goodsId
    this.name = params.goodsName
  }
}
四、路由栈管理实战
登录成功清空栈跳首页:router.clear()后 push 首页;
弹窗点击跳转页面,返回关闭弹窗;
路由拦截:未登录拦截跳转登录页。
五、搭配 Tabs 底部导航
Tabs 内部页面切换使用路由,实现独立页面生命周期。
六、踩坑
跳转空白页面:pages 路由路径写错;
参数接收不到:aboutToAppear 生命周期读取;
页面多次叠加:使用 replaceUrl 避免重复入栈。
七、适用场景
首页跳详情、登录跳转首页、商品列表跳转购物车、返回上一页。


博客 19:ArkTS onChange 事件全解析|输入、开关、单选、轮播统一监听语法
一、onChange 通用语法
所有具备状态变化的组件统一回调格式:
ets
onChange(()=>{
  // 状态变化业务逻辑
})
// 带参数写法(组件会自动传递当前值/索引)
onChange((value)=>{
  console.info("变更值:", value)
})
二、各组件 onChange 使用场景
1. TextInput 输入框
输入文字实时触发,获取输入字符串:
ets
TextInput().onChange((text:string)=>{
  this.inputVal = text
})
2. Toggle 开关
切换开关,返回布尔 true/false:
ets
Toggle().onChange((isOpen:boolean)=>{
  this.msgSwitch = isOpen
})
3. Radio 单选框
切换选项,返回选中 value 字符串:
ets
RadioGroup().onChange((select:string)=>{
  this.gender = select
})
4. Swiper 轮播图
滑动切换页面,返回当前索引数字:
ets
Swiper().onChange((index:number)=>{
  this.curBannerIdx = index
})
5. Tabs 选项卡
切换标签,返回当前 Tab 索引:
ets
Tabs().onChange((tabIdx:number)=>{
  this.currentTab = tabIdx
})
三、onChange 核心用途
同步更新 @State 状态变量,驱动 UI 刷新;
实时表单校验(手机号、密码长度判断);
联动其他组件状态(选分类自动刷新列表);
记录用户操作、埋点日志。
四、onChange 与 onClick 区别
onChange:组件内部状态发生改变时触发(输入、切换、滑动);
onClick:用户点击组件时触发(手指触摸点击动作)。
五、实战:表单联动校验
输入框 onChange 实时判断输入长度,按钮动态启用 / 禁用。
六、踩坑
忘记接收回调参数,无法获取新值;
未给 @State 变量赋值,UI 状态不更新。
七、适用场景
所有可交互组件状态监听、表单实时处理、切换联动逻辑


博客 20:ArkTS onClick 点击事件完整教程|任意组件点击、跳转、弹窗
一、onClick 标准基础语法
任意 UI 组件(Button/Text/Image/Row/Column)都支持绑定点击事件,标准箭头函数写法:
ets
onClick(()=>{
  // 点击执行逻辑
})
二、各类组件点击示例
1. Button 按钮点击(登录提交)
ets
Button("登录")
  .onClick(()=>{
    // 调用登录接口、路由跳转首页
  })
2. Text 文字点击(跳转找回密码)
ets
Text("忘记密码")
  .fontColor("#007dff")
  .onClick(()=>{
    router.pushUrl({url:"pages/findPwd/findPwd"})
  })
3. Image 图片点击(图片预览)
ets
Image($r("app.media.goods"))
  .onClick(()=>{
    // 打开大图预览弹窗
  })
4. Row 整行点击(列表条目)
ets
Row() {
  Image($r("app.media.icon"))
  Text("列表条目")
}
.onClick(()=>{
  // 跳转详情页
})
三、点击传参写法
封装工具方法,点击时传递参数:
ets
handleClick(id:number) {
  router.pushUrl({url:"pages/detail/detail", params:{id}})
}

// 调用
Text("商品1")
  .onClick(()=>this.handleClick(1001))
四、防重复点击节流优化
设置 @State 标记锁,短时间多次点击拦截:
ets
@State isClickLock: boolean = false

Button("提交")
  .onClick(()=>{
    if(this.isClickLock) return
    this.isClickLock = true
    // 业务逻辑
    setTimeout(()=>{
      this.isClickLock = false
    }, 1000)
  })
五、onClick 常用业务场景
页面路由跳转;
唤起 Alert、CustomDialog 弹窗;
发起接口请求(提交表单、删除数据);
修改 @State 状态变量(显示隐藏面板)。
六、和 onChange 区分
onClick 是点击手势动作,onChange 是组件内部数据 / 状态变更,二者经常搭配使用。
七、踩坑
大面积容器点击无响应:容器未设置宽高;
多次重复点击重复请求:添加节流锁。
八、适用场景
按钮提交、文字跳转、列表条目点击、图片预览、弹窗唤起、功能操作按钮。


博客 21:综合实战博客:鸿蒙完整登录页面|布局 + 组件 + 状态 + 事件 + 路由全整合
一、前言
本文整合前面全部知识点,从零实现一套完整登录页面,包含:
布局:根布局 Column、嵌套 Row、Stack 遮罩弹窗;
组件:Image、Text、TextInput、Button、Toggle;
状态:@State 管理账号、密码、记住密码开关;
事件:onChange 监听输入、onClick 登录 / 弹窗 / 跳转;
拓展:Alert 弹窗、Router 路由跳转。
二、完整可运行代码
ets
import router from '@ohos.router'

@Entry
@Component
struct LoginPage {
  // @State响应式状态管理
  @State account: string = ""
  @State password: string = ""
  @State rememberPwd: boolean = true

  // 登录校验逻辑
  doLogin() {
    if(this.account.length < 6) {
      AlertDialog.show({message:"账号至少6位"})
      return
    }
    if(this.password.length < 6) {
      AlertDialog.show({message:"密码至少6位"})
      return
    }
    // 登录成功跳转首页
    router.clear()
    router.pushUrl({url:"pages/index/index"})
  }

  goFindPwd() {
    router.pushUrl({url:"pages/findPwd/findPwd"})
  }

  build() {
    // 唯一根布局 Column
    Column() {
      // Logo图片
      Image($r("app.media.logo"))
        .width(100)
        .height(100)
        .margin({bottom:30})

      // 账号输入框
      TextInput({text: this.account, placeholder:"请输入账号"})
        .width("100%")
        .height(44)
        .padding(10)
        .border({width:1, color:"#eee"})
        .borderRadius(8)
        .onChange((val:string)=>{
          // onChange实时同步账号状态
          this.account = val
        })

      // 密码输入框
      TextInput({text: this.password, placeholder:"请输入密码"})
        .width("100%")
        .height(44)
        .margin({top:15})
        .padding(10)
        .border({width:1, color:"#eee"})
        .borderRadius(8)
        .type(InputType.Password)
        .onChange((val:string)=>{
          this.password = val
        })
      
      // 记住密码 + 忘记密码 水平Row布局
      Row() {
        Row() {
          Toggle({isOn: this.rememberPwd})
            .width(40)
            .onChange((status:boolean)=>{
              this.rememberPwd = status
            })
          Text("记住密码").fontSize(14).margin({left:6})
        }
        Text("忘记密码?")
          .fontSize(14)
          .fontColor("#007dff")
          .onClick(()=>this.goFindPwd())
      }
      .width("100%")
      .margin({top:15})
      .justifyContent(FlexAlign.SpaceBetween)
      .alignItems(ItemAlign.Center)

      // 登录按钮
      Button("登录", {type:ButtonType.Normal})
        .width("100%")
        .height(48)
        .margin({top:30})
        .backgroundColor("#007dff")
        .borderRadius(8)
        .onClick(()=>this.doLogin())

      // 注册文字按钮
      Text("没有账号?立即注册")
        .fontSize(14)
        .fontColor("#007dff")
        .margin({top:20})
        .onClick(()=>{
          router.pushUrl({url:"pages/register/register"})
        })
    }
    .width("100%")
    .height("100%")
    .padding(25)
    .justifyContent(FlexAlign.Center)
  }
}
三、知识点对应梳理
布局:根布局 Column,内部嵌套 Row 实现记住密码行;
组件:Image、Text、TextInput、Button、Toggle 全部使用;
状态:@State 维护账号、密码、开关状态;
onChange:输入框、开关状态实时同步;
onClick:登录、找回密码、注册页面点击跳转;
弹窗:AlertDialog 表单校验提示;
路由:router 页面跳转、清空栈跳转首页。
四、页面功能说明
账号密码实时输入监听,长度校验弹窗提示;
记住密码 Toggle 开关状态保存;
忘记密码、注册文字点击跳转对应页面;
登录成功清空路由栈,跳转首页。
五、拓展优化方向
增加自定义弹窗协议勾选;
接入网络登录接口;
使用本地存储持久化记住密码;
添加输入框清空按钮、验证码登录。
六、总结
本页面覆盖文档全部基础知识点,是鸿蒙 ArkTS 入门标准综合实战,吃透该案例即可掌握页面布局、组件、状态、事件、路由、弹窗全套基础开发能力。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐