自学 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)
  }
}总结:自定义组件的三层境界
自学写作不易,希望大家喜欢,点赞、关注、收藏~
©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
  标签 
   
        赞
        
 
        收藏 
      
 回复
  回复
     相关推荐
 



















