第5章:数据驱动UI
自定义组件
1. 自定义组件概述
在ArkTS中,自定义组件是开发者根据业务需求封装的可复用UI单元。通过组合基础组件和实现特定逻辑,可以创建具有独立功能与样式的组件。
核心优势:
- 提高代码复用率
- 实现业务逻辑隔离
- 增强项目可维护性
2. 创建自定义组件
2.1 基本结构
@Component
struct CustomComponent {
// 组件状态变量
@State private count: number = 0
// UI描述
build() {
Column() {
Text(`点击次数: ${this.count}`)
.fontSize(20)
Button('点击增加')
.onClick(() => {
this.count++
})
}
}
}
2.2 关键注解说明
| 注解 | 作用 |
|---|---|
@Component | 标识为可复用的自定义组件 |
@State | 组件内部状态,变化触发UI更新 |
@Prop | 从父组件单向同步的不可变数据 |
@Link | 与父组件双向绑定的可变数据 |
3. 组件参数传递
3.1 父向子传参
// 子组件
@Component
struct ChildComponent {
@Prop message: string
build() {
Text(this.message)
}
}
// 父组件使用
ChildComponent({ message: 'Hello from parent' })
3.2 双向数据绑定
// 子组件
@Component
struct Counter {
@Link value: number
build() {
Button(`Add`).onClick(() => this.value++)
}
}
// 父组件
@Entry
@Component
struct Parent {
@State count: number = 0
build() {
Column() {
Text(`Parent count: ${this.count}`)
Counter({ value: $count }) // 使用$符号建立双向绑定
}
}
}
4. 组件生命周期
ArkTS自定义组件提供完整的生命周期回调:
@Component
struct LifecycleDemo {
// 初始化时执行(API 9+)
aboutToAppear() {
console.log('组件即将出现')
}
// 构建UI
build() {
/*...*/
}
// 组件销毁时执行(API 9+)
aboutToDisappear() {
console.log('组件即将销毁')
}
}
5. 组件样式封装
5.1 样式隔离
通过@Styles和@Extend实现样式复用:
// 定义可复用样式
@Styles function fancyText() {
.fontSize(20)
.fontColor('#FF1493')
}
// 使用样式
Text('Stylish Text')
.useStyle(fancyText)
5.2 主题适配
@Component
struct ThemedComponent {
@StorageLink('darkMode') isDark: boolean = false
build() {
Column() {
Text('主题敏感组件')
.fontColor(this.isDark ? '#FFFFFF' : '#000000')
.backgroundColor(this.isDark ? '#222222' : '#F5F5F5')
}
}
}
6. 最佳实践
- 单一职责原则:每个组件只负责一个特定功能
- 合理拆分:当组件超过300行代码时考虑拆分
- 性能优化:
- 避免在build()中进行复杂计算
- 使用
@ObjectLink处理深层对象变化
- 文档规范:使用TSDoc为组件编写使用说明
/**
* 带计数功能的按钮组件
* @param initialValue 初始计数值
* @param onCountChange 计数变化回调
*/
@Component
struct CounterButton {
@State private count: number = 0
private initialValue: number = 0
private onCountChange?: (count: number) => void
// ...
}
7. 复杂组件示例:下拉刷新组件
@Component
export struct RefreshableList {
@State isRefreshing: boolean = false
@Prop data: Array<string>
@State private scrollController: ScrollController = new ScrollController()
build() {
Stack() {
List({ space: 10, controller: this.scrollController }) {
ForEach(this.data, (item) => {
ListItem() {
Text(item)
.height(60)
}
})
}
.onScrollEdge((edge) => {
if (edge === ScrollEdge.Top && !this.isRefreshing) {
this.startRefresh()
}
})
if (this.isRefreshing) {
LoadingProgress()
.width(50)
.height(50)
}
}
}
private startRefresh() {
this.isRefreshing = true
// 模拟异步加载
setTimeout(() => {
this.isRefreshing = false
}, 1500)
}
}
调试技巧:在DevEco Studio中使用组件预览器(Component Previewer)可以独立调试自定义组件,无需嵌入完整页面。
