HarmonyOS鸿蒙Next中如何使用@Component创建自定义组件?@Prop和@Link如何实现父子通信?

HarmonyOS鸿蒙Next中如何使用@Component创建自定义组件?@Prop@Link如何实现父子通信? 我想在 HarmonyOS 应用中封装可复用的 UI 组件,想了解:

  1. @Component 装饰器的作用是什么?组件的基本结构包括哪些部分?

  2. 如何通过 @Prop 接收父组件传递的属性?

  3. @Link 如何实现父子组件的双向数据绑定?

  4. 如何使用 export 导出组件供其他文件使用?

  5. 组件的生命周期方法(aboutToAppear、aboutToDisappear)如何使用?

希望能获取自定义组件的完整封装示例。


更多关于HarmonyOS鸿蒙Next中如何使用@Component创建自定义组件?@Prop和@Link如何实现父子通信?的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

实现思路:

  1. 使用 @Component 装饰器定义自定义组件,使用 @Prop 接收父组件传递的属性(单向):
[@Component](/user/Component)
export struct GlassCard {
  [@Prop](/user/Prop) title: string = '';
  [@Prop](/user/Prop) subtitle: string = '';

  build() {
    Column() {
      Text(this.title).fontSize(16).fontWeight(FontWeight.Bold)
      Text(this.subtitle).fontSize(12).fontColor('#666')
    }
    .padding(16)
    .backgroundColor('#FFFFFF')
    .borderRadius(12)
  }
}
  1. 使用 @Link 实现父子组件双向数据绑定,子组件修改会同步到父组件:
[@Component](/user/Component)
export struct ToggleCard {
  [@Prop](/user/Prop) title: string = '';
  [@Link](/user/Link) isOn: boolean;  // 双向绑定

  build() {
    Row() {
      Text(this.title)
      Blank()
      Toggle({ type: ToggleType.Switch, isOn: this.isOn })
        .onChange((value: boolean) => this.isOn = value)
    }
    .width('100%')
    .padding(16)
  }
}
  1. 父组件使用子组件,@Prop 直接传值,@Link 使用 $ 前缀:
@Entry
[@Component](/user/Component)
struct ParentPage {
  @State switchOn: boolean = false;

  build() {
    Column({ space: 16 }) {
      // [@Prop](/user/Prop):直接传值
      GlassCard({ title: '标题', subtitle: '副标题' })
      
      // [@Link](/user/Link):使用 $ 前缀
      ToggleCard({ title: '开关设置', isOn: $switchOn })
      
      Text(`当前状态: ${this.switchOn}`)
    }
    .padding(16)
  }
}
  1. 完整示例代码:
// components/GlassCard.ets
[@Component](/user/Component)
export struct GlassCard {
  [@Prop](/user/Prop) title: string = '';
  [@Prop](/user/Prop) subtitle: string = '';
  [@Prop](/user/Prop) icon: Resource | null = null;
  [@Link](/user/Link) isExpanded: boolean;
  @BuilderParam content: () => void = this.defaultContent;

  @Builder defaultContent() {
    Text('默认内容')
  }

  build() {
    Column({ space: 8 }) {
      Row() {
        if (this.icon) {
          Image(this.icon).width(24).height(24)
        }
        Column() {
          Text(this.title).fontSize(16).fontWeight(FontWeight.Bold)
          if (this.subtitle) {
            Text(this.subtitle).fontSize(12).fontColor('#666')
          }
        }
        .alignItems(HorizontalAlign.Start)
        Blank()
        Image($r('app.media.arrow'))
          .width(16)
          .rotate({ angle: this.isExpanded ? 90 : 0 })
      }
      .width('100%')
      .onClick(() => this.isExpanded = !this.isExpanded)

      if (this.isExpanded) {
        this.content()
      }
    }
    .padding(16)
    .backgroundColor('#FFFFFF')
    .borderRadius(12)
  }
}

// pages/MainPage.ets
@Entry
[@Component](/user/Component)
struct MainPage {
  @State cardExpanded: boolean = false;

  build() {
    Column({ space: 16 }) {
      GlassCard({
        title: '卡片标题',
        subtitle: '点击展开',
        isExpanded: $cardExpanded
      }) {
        Column({ space: 8 }) {
          Text('展开的内容第一行')
          Text('展开的内容第二行')
          Button('操作按钮')
        }
      }
    }
    .padding(16)
  }
}

更多关于HarmonyOS鸿蒙Next中如何使用@Component创建自定义组件?@Prop和@Link如何实现父子通信?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,使用@Component装饰器创建自定义组件。示例:@Component struct MyComponent { ... }

@Prop用于父组件向子组件传递单向数据,子组件修改不会影响父组件。@Link实现双向数据绑定,父子组件数据同步更新。

在父组件中使用时,用@State装饰变量,子组件中用@Prop@Link接收。

在HarmonyOS Next中,使用[@Component](/user/Component)创建自定义组件并实现通信,是构建模块化UI的核心。以下是针对你问题的解答:

1. @Component装饰器与组件结构

[@Component](/user/Component)装饰器用于标记一个自定义组件,使其具备独立的UI、状态和生命周期。基本结构包括:

  • 装饰器[@Component](/user/Component)
  • 结构体:包含组件状态变量(@State, [@Prop](/user/Prop), [@Link](/user/Link)等)和UI描述(build()方法)
  • build()方法:必需,用于描述UI布局

示例结构:

[@Component](/user/Component)
struct MyComponent {
  // 状态变量
  @State message: string = 'Hello'

  // UI描述
  build() {
    // 返回UI组件树
  }
}

2. @Prop:单向属性传递

[@Prop](/user/Prop)用于接收父组件传递的只读数据,实现单向同步:

  • 父组件修改数据会同步到子组件
  • 子组件不能直接修改[@Prop](/user/Prop)变量(修改不会同步回父组件)

示例:

// 子组件
[@Component](/user/Component)
struct ChildComponent {
  [@Prop](/user/Prop) title: string  // 接收父组件传递的title
  
  build() {
    Text(this.title)
  }
}

// 父组件
@Entry
[@Component](/user/Component)
struct ParentComponent {
  @State parentTitle: string = '父组件标题'
  
  build() {
    Column() {
      // 传递数据给子组件
      ChildComponent({ title: this.parentTitle })
    }
  }
}

3. @Link:双向数据绑定

[@Link](/user/Link)建立父子组件间的双向同步:

  • 父组件和子组件共享同一数据源
  • 任何一方的修改都会同步到另一方

示例:

// 子组件
[@Component](/user/Component)
struct ChildComponent {
  [@Link](/user/Link) @Watch('onCountChange') count: number  // 双向绑定
  
  onCountChange() {
    console.log('count changed:', this.count)
  }
  
  build() {
    Button('子组件+1')
      .onClick(() => {
        this.count++  // 修改会同步到父组件
      })
  }
}

// 父组件
@Entry
[@Component](/user/Component)
struct ParentComponent {
  @State count: number = 0
  
  build() {
    Column() {
      Text(`父组件count: ${this.count}`)
      ChildComponent({ count: $count })  // 使用$符号建立双向绑定
    }
  }
}

4. 导出组件

使用export关键字导出组件,使其可在其他文件中导入使用:

// MyComponent.ets
[@Component](/user/Component)
export struct MyComponent {  // 添加export
  [@Prop](/user/Prop) message: string
  
  build() {
    Text(this.message)
  }
}

// 在其他文件中导入
import { MyComponent } from './MyComponent'

@Entry
[@Component](/user/Component)
struct MainPage {
  build() {
    MyComponent({ message: '导入的组件' })
  }
}

5. 生命周期方法

  • aboutToAppear():组件即将出现时调用,用于初始化操作
  • aboutToDisappear():组件即将销毁时调用,用于清理资源

示例:

[@Component](/user/Component)
struct LifecycleComponent {
  @State data: string = ''
  
  aboutToAppear() {
    // 组件显示前初始化
    this.data = '初始化数据'
    console.log('组件即将显示')
  }
  
  aboutToDisappear() {
    // 组件销毁前清理
    console.log('组件即将销毁')
  }
  
  build() {
    Text(this.data)
  }
}

完整示例:封装计数器组件

// CounterComponent.ets
[@Component](/user/Component)
export struct CounterComponent {
  [@Link](/user/Link) value: number  // 双向绑定计数器值
  [@Prop](/user/Prop) label: string = '计数器'  // 单向接收标签
  
  aboutToAppear() {
    console.log('计数器组件初始化')
  }
  
  build() {
    Column() {
      Text(`${this.label}: ${this.value}`)
        .fontSize(20)
      
      Row() {
        Button('-')
          .onClick(() => this.value--)
        
        Button('+')
          .onClick(() => this.value++)
      }
    }
  }
}

// 使用组件
@Entry
[@Component](/user/Component)
struct MainPage {
  @State count: number = 0
  
  build() {
    Column() {
      CounterComponent({
        value: $count,  // 双向绑定
        label: '点击计数'  // 单向传递
      })
    }
  }
}

关键点总结

  • [@Component](/user/Component)定义可复用UI单元,必须包含build()方法
  • [@Prop](/user/Prop)实现父到子的单向数据流,适合展示型组件
  • [@Link](/user/Link)实现父子双向同步,适合交互型组件
  • export使组件可跨文件复用
  • 生命周期方法用于资源管理,注意aboutToAppear中避免耗时操作

这种组件化模式支持高内聚、低耦合的UI开发,通过组合[@Prop](/user/Prop)[@Link](/user/Link)可以灵活处理各种父子通信场景。

回到顶部