HarmonyOS鸿蒙Next中如何在应用中创建和使用自定义组件?
HarmonyOS鸿蒙Next中如何在应用中创建和使用自定义组件? 如何在鸿蒙应用中创建可复用的自定义组件?如何在不同页面中使用这些组件?
关键字:自定义组件、@Component、组件复用、Props、组件通信
回答
原理解析
自定义组件是ArkTS中实现代码复用和模块化的核心机制。通过[@Component](/user/Component)装饰器创建可复用的UI组件。
核心概念:
- @Component装饰器:标记为可复用组件
- Props传递:使用
[@Prop](/user/Prop)、@Link、@State等装饰器接收参数 - 组件生命周期:
aboutToAppear、aboutToDisappear - 组件导出:使用
export关键字导出组件供其他模块使用
装饰器类型:
[@Prop](/user/Prop):从父组件接收只读属性@Link:与父组件双向绑定@State:组件内部状态@Builder:构建函数,用于构建UI片段
详细解决步骤
步骤1:创建基础组件
[@Component](/user/Component)
export struct MyCard {
title: string = ''
content: string = ''
build() {
Column({ space: 10 }) {
Text(this.title)
Text(this.content)
}
.padding(15)
.backgroundColor('FFFFFF')
.borderRadius(8)
}
}
步骤2:使用@Prop接收参数
[@Component](/user/Component)
export struct UserCard {
[@Prop](/user/Prop) userName: string = ''
[@Prop](/user/Prop) userAge: number = 0
build() {
Row() {
Text(this.userName)
Text(`${this.userAge}岁`)
}
}
}
步骤3:在页面中使用组件
@Entry
[@Component](/user/Component)
struct Index {
build() {
Column() {
MyCard({ title: '标题', content: '内容' })
UserCard({ userName: '张三', userAge: 25 })
}
}
}
示例代码
完整示例:自定义组件库
- 卡片组件(CardComponent.ets):
[@Component](/user/Component)
export struct CardComponent {
[@Prop](/user/Prop) title: string = ''
[@Prop](/user/Prop) content: string = ''
[@Prop](/user/Prop) backgroundColor: string = 'FFFFFF'
[@Prop](/user/Prop) onCardClick?: () => void
build() {
Column({ space: 12 }) {
Text(this.title)
.fontSize(18)
.fontWeight(FontWeight.Bold)
.fontColor('182431')
Text(this.content)
.fontSize(14)
.fontColor('666666')
.maxLines(3)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.width('100%')
.padding(20)
.backgroundColor(this.backgroundColor)
.borderRadius(12)
.shadow({
radius: 8,
color: '1F000000',
offsetX: 0,
offsetY: 2
})
.onClick(() => {
if (this.onCardClick) {
this.onCardClick()
}
})
}
}
- 按钮组件(ButtonComponent.ets):
[@Component](/user/Component)
export struct ButtonComponent {
[@Prop](/user/Prop) text: string = ''
[@Prop](/user/Prop) type: 'primary' | 'secondary' | 'danger' = 'primary'
[@Prop](/user/Prop) disabled: boolean = false
private onClickHandler?: () => void
build() {
Button(this.text)
.width('100%')
.height(50)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.backgroundColor(this.getBackgroundColor())
.fontColor(this.getFontColor())
.borderRadius(8)
.enabled(!this.disabled)
.opacity(this.disabled ? 0.5 : 1)
.onClick(() => {
if (this.onClickHandler && !this.disabled) {
this.onClickHandler()
}
})
}
private getBackgroundColor(): string {
if (this.disabled) return 'CCCCCC'
switch (this.type) {
case 'primary': return '007DFF'
case 'secondary': return 'F1F3F5'
case 'danger': return 'FF3B30'
default: return '007DFF'
}
}
private getFontColor(): string {
if (this.disabled) return '999999'
return this.type === 'secondary' ? '182431' : 'FFFFFF'
}
// 设置点击事件
setOnClick(handler: () => void): ButtonComponent {
this.onClickHandler = handler
return this
}
}
- 列表项组件(ListItemComponent.ets):
[@Component](/user/Component)
export struct ListItemComponent {
[@Prop](/user/Prop) icon: string = ''
[@Prop](/user/Prop) title: string = ''
[@Prop](/user/Prop) subtitle: string = ''
[@Prop](/user/Prop) showArrow: boolean = true
private onItemClick?: () => void
build() {
Row({ space: 15 }) {
if (this.icon) {
Text(this.icon)
.fontSize(24)
}
Column({ space: 5 }) {
Text(this.title)
.fontSize(16)
.fontWeight(FontWeight.Medium)
.fontColor('182431')
if (this.subtitle) {
Text(this.subtitle)
.fontSize(14)
.fontColor('666666')
}
}
.layoutWeight(1)
if (this.showArrow) {
Text('>')
.fontSize(18)
.fontColor('CCCCCC')
}
}
.width('100%')
.padding(15)
.backgroundColor('FFFFFF')
.borderRadius(8)
.onClick(() => {
if (this.onItemClick) {
this.onItemClick()
}
})
}
setOnClick(handler: () => void): ListItemComponent {
this.onItemClick = handler
return this
}
}
- 使用示例(Index.ets):
import { CardComponent } from '../components/CardComponent'
import { ButtonComponent } from '../components/ButtonComponent'
import { ListItemComponent } from '../components/ListItemComponent'
@Entry
[@Component](/user/Component)
struct Index {
@State cardTitle: string = '欢迎使用'
@State cardContent: string = '这是一个自定义组件示例'
build() {
Column({ space: 20 }) {
// 使用卡片组件
CardComponent({
title: this.cardTitle,
content: this.cardContent,
backgroundColor: 'E3F2FD',
onCardClick: () => {
console.info('卡片被点击')
}
})
// 使用按钮组件
ButtonComponent({
text: '主要按钮',
type: 'primary'
}).setOnClick(() => {
this.cardTitle = '按钮已点击'
this.cardContent = '内容已更新'
})
ButtonComponent({
text: '次要按钮',
type: 'secondary'
}).setOnClick(() => {
console.info('次要按钮点击')
})
ButtonComponent({
text: '禁用按钮',
type: 'danger',
disabled: true
})
// 使用列表项组件
ListItemComponent({
icon: '⚙️',
title: '设置',
subtitle: '应用设置和偏好',
showArrow: true
}).setOnClick(() => {
console.info('设置被点击')
})
ListItemComponent({
icon: 'ℹ️',
title: '关于',
subtitle: '版本信息',
showArrow: true
})
}
.width('100%')
.height('100%')
.padding(20)
.backgroundColor('F1F3F5')
}
}
高级用法
- 组件状态管理
[@Component](/user/Component)
export struct CounterComponent {
@State count: number = 0
build() {
Column() {
Text(`计数: ${this.count}`)
Button('增加')
.onClick(() => {
this.count++
})
}
}
}
- 组件事件传递
[@Component](/user/Component)
export struct InputComponent {
@State inputValue: string = ''
private onValueChange?: (value: string) => void
build() {
TextInput({ text: this.inputValue })
.onChange((value: string) => {
this.inputValue = value
if (this.onValueChange) {
this.onValueChange(value)
}
})
}
setOnValueChange(handler: (value: string) => void): InputComponent {
this.onValueChange = handler
return this
}
}
- 组件组合
[@Component](/user/Component)
export struct FormComponent {
[@Prop](/user/Prop) title: string = ''
build() {
Column({ space: 15 }) {
Text(this.title)
.fontSize(20)
.fontWeight(FontWeight.Bold)
InputComponent()
.setOnValueChange((value: string) => {
console.info('输入值:', value)
})
ButtonComponent({
text: '提交',
type: 'primary'
})
}
}
}
常见问题
Q: 如何实现组件间的双向绑定?
A: 使用@Link装饰器,父组件传递时使用$符号:ChildComponent({ value: $parentValue })
Q: 组件如何接收函数参数?
A: 定义可选的回调函数属性,使用?:标记为可选。
Q: 如何导出组件供其他模块使用?
A: 使用export关键字导出组件,在其他文件中使用import导入。
总结:自定义组件是代码复用的基础,掌握组件的创建、参数传递和事件处理是构建可维护应用的关键。
更多关于HarmonyOS鸿蒙Next中如何在应用中创建和使用自定义组件?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
在HarmonyOS Next中创建自定义组件,需在ets目录下新建.ets文件,使用@Component装饰器定义组件结构,通过@BuilderParam实现动态UI构建。组件内可封装私有状态与布局逻辑,支持@Prop、@Link等装饰器进行数据传递。使用时直接导入并声明组件标签,可复用并嵌入到其他页面或组件中。
在HarmonyOS Next中,创建和使用自定义组件是构建应用的基础。以下是具体方法:
1. 创建自定义组件
- 在
ets目录下新建.ets文件(如MyComponent.ets)。 - 使用
[@Component](/user/Component)装饰器定义组件结构,例如:[@Component](/user/Component) struct MyComponent { @State message: string = 'Hello' build() { Column() { Text(this.message) .fontSize(20) } } }
2. 导出组件
在组件文件中使用export导出,以便其他文件导入:
export { MyComponent }
3. 在其他页面中使用
- 在需要使用的页面(如
Index.ets)中导入组件:import { MyComponent } from './MyComponent' - 在
build()方法中直接调用:[@Entry](/user/Entry) [@Component](/user/Component) struct Index { build() { Column() { MyComponent() } } }
4. 组件传参
通过@Prop或@Link装饰器实现参数传递:
[@Component](/user/Component)
struct MyComponent {
@Prop title: string // 父组件向子组件传参
build() {
Text(this.title)
}
}
使用时传递参数:
MyComponent({ title: '自定义标题' })
5. 组件样式复用
- 样式可提取为单独函数或常量。
- 支持动态样式绑定。
关键点
- 组件必须用
[@Component](/user/Component)装饰。 build()方法返回UI描述。- 通过
export/import实现模块化。 - 使用装饰器(
@Prop、@Link、@State等)管理数据状态。
这种方式能有效提高代码复用性和可维护性。

