
自学 HarmonyOS ArkTS 自定义组件:打造可复用的 UI 架构 原创
李森同学
发布于 2025-3-27 10:40
浏览
0收藏
一、自定义组件:构建 UI 的原子化思维
核心特性(官方定义重构)
- 可组合性:封装系统组件(如 Row+Text)为复合组件
- 可复用性:跨页面 / 跨项目的组件实例化(如 ButtonGroup)
- 数据驱动:@State 变量触发 UI 自动刷新(区别于命令式编程)
基础语法(代码重构示例)
// 自定义按钮组件(修改参数名+样式)
@Component
struct CustomButton {
@State btnText: string = '点击我' // 状态变量
@State btnColor: Color = Color.RoyalBlue // 初始样式
// 自定义点击事件(新增业务逻辑)
handleClick() {
this.btnText = `已点击${++this.clickCount}次`
console.info(`按钮状态更新:${this.btnText}`) // 合法的日志位置
}
build() {
Button(this.btnText)
.fontSize(16)
.padding(12)
.backgroundColor(this.btnColor)
.onClick(() => this.handleClick()) // 绑定自定义逻辑
}
}
// 父组件调用(多实例复用)
@Entry
@Component
struct AppComponent {
build() {
Column {
CustomButton() // 默认实例
.margin(10)
.width(150)
CustomButton({ btnText: '提交', btnColor: Color.Green }) // 定制实例
.margin(10)
.width(200)
}
}
}
二、组件元编程:装饰器的魔法世界
核心装饰器对比(表格重构)
装饰器 | 作用场景 | 版本支持 | 扩展参数 |
@Component | 基础组件封装 | API 7+ | freezeWhenInactive(API 11+) |
@Entry | 页面入口组件 | API 7+ | routeName/storage(API 10+) |
@Reusable | 可复用组件(跨模块) | API 10+ | - |
高级用法:组件冻结优化(新增示例)
// 长列表组件(开启冻结优化)
@Component({ freezeWhenInactive: true })
struct ListItem {
@State itemData: any
build() {
Row {
Text(itemData.title).fontSize(14)
Text(itemData.date).fontSize(12).opacity(0.7)
}.height(60)
}
}
三、build () 函数:UI 描述的黄金法则
合法操作清单(流程图解)
build() 函数 → [ 根节点唯一 ] → [ 容器组件(@Entry)/任意组件(@Component) ]
↳ 禁止:本地变量/switch/表达式/直接状态修改
↳ 允许:if条件/@Builder方法/TS函数返回值
反模式与解决方案(真实案例)
@State count: number = 0
build() {
Text(`计数:${this.count++}`) // ❌ 每次渲染改变状态
.onClick(() => this.count += 2)
}
@State count: number = 0
handleCount() {
this.count++ // ✅ 仅在事件处理中变更
}
build() {
Text(`计数:${this.count}`)
.onClick(this.handleCount)
}
四、父子组件通信:数据流的双向通道
实战模式:
// 子组件
@Component
struct ChildComponent {
propTitle: string // 父组件传入的属性
build() { Text(propTitle) }
}
// 父组件
ChildComponent({ propTitle: '来自父组件的标题' })
.fontSize(18)
// 子组件
@Component
struct ButtonGroup {
onSubmit: () => void // 回调函数定义
build() {
Button('提交')
.onClick(() => this.onSubmit()) // 触发回调
}
}
// 父组件
@State formData: any = {}
handleSubmit() {
console.info('提交数据:', formData)
}
ButtonGroup({ onSubmit: this.handleSubmit })
五、状态管理:性能优化的关键
状态变更最佳实践:
@State user: { name: string, age: number } = { name: 'Alice', age: 25 }
build() {
Row {
Text(user.name).fontSize(16) // 仅name变更时更新
Text(user.age.toString()).fontSize(14) // 仅age变更时更新
}
}
@State list: number[] = [1, 2, 3]
// 错误:直接修改原数组(触发不必要渲染)
handleSort() {
this.list.sort() // ❌ 改变原数组
}
// 正确:创建新数组(精确触发更新)
handleSort() {
this.list = [...this.list].sort() // ✅ 新数组引用
}
六、样式系统:组件封装的视觉规范
样式继承机制(深度解析):
@Component
struct CardComponent {
build() {
Column {
Text('标题').fontSize(20)
Text('内容').fontSize(14).margin(8)
}
.padding(16)
.backgroundColor(Color.White)
.borderRadius(8)
.shadow(4, 4, 8, Color.Gray.withAlpha(0.1))
}
}
// 父组件样式覆盖
CardComponent()
.width('90%') // 容器样式(不可见包裹层)
.margin({ top: 12, bottom: 12 })
.backgroundColor(Color.LightGray) // 覆盖内部背景
七、实战案例:倒计时组件(完整实现)
// 自定义倒计时组件
@Component
struct CountdownTimer {
@State seconds: number = 60 // 初始倒计时
@State isRunning: boolean = false
// 生命周期方法(模拟)
onStart() {
this.isRunning = true
setInterval(() => {
if (this.seconds > 0) this.seconds--
else this.isRunning = false
}, 1000)
}
build() {
Row {
Text(`${this.seconds}s`)
.fontSize(24)
.fontWeight(FontWeight.Bold)
.color(this.isRunning ? Color.Red : Color.Gray)
if (this.isRunning) {
Button('暂停')
.onClick(() => this.isRunning = false)
} else {
Button('开始')
.onClick(this.onStart)
}
}
.padding(16)
.borderRadius(12)
.backgroundColor(Color.White)
}
}
// 页面使用
@Entry
@Component
struct TimerPage {
build() {
Column {
CountdownTimer() // 默认60秒
.margin(20)
CountdownTimer({ seconds: 120 }) // 定制为2分钟
.margin(20)
}
.justifyContent(FlexAlign.Center)
.backgroundColor(Color.Background)
}
}
总结:自定义组件的三层境界
自学写作不易,希望大家喜欢,点赞、关注、收藏~
©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
赞
收藏
回复

回复
相关推荐