鸿蒙 ArkTS 自定义组件全攻略:从按钮到商品卡片一步步搞定

摘要

在做应用开发的时候,我们经常会遇到这样的需求:系统提供的原生组件虽然能用,但总感觉差点意思。比如按钮样式不够个性化、输入框逻辑不够灵活、组件复用不够方便。这时候,自定义组件就是解题思路。在鸿蒙(HarmonyOS, ArkTS 开发)里,实现自定义组件并不复杂,甚至和 React/Vue 这些框架有点类似。你只要会封装 UI 和逻辑,就能把它们做成像系统组件一样随用随取的模块。

引言

随着鸿蒙生态逐渐成熟,开发者不仅要会用系统组件,更要能根据实际场景封装自己的组件。举个例子:

  • 如果你在做一个表单应用,那可能需要一个"带错误提示的输入框组件"。
  • 如果你在做一个商城类应用,那可能需要一个"带点击效果的商品卡片组件"。
  • 如果你在做一个工具类应用,那可能需要一个"支持动态切换状态的按钮"。

这些场景都指向一个关键技能:自定义组件。本文会从最基础的入门讲起,再带你通过实战 Demo 和场景案例把这个技能用熟。

基础概念:怎么写一个自定义组件

在鸿蒙的 ArkTS 开发中,实现一个自定义组件的关键点主要有:

@Component 定义组件类 组件的 UI 在 build() 方法里写。

@Prop 接收外部参数 类似 Vue 的 props,父组件传值,子组件接收。

@State 管理内部状态 内部逻辑变化会触发 UI 更新。

像系统组件一样使用 在父组件中直接 <MyComponent /> 即可。

可运行 Demo:自定义按钮

我们先从一个最简单的按钮组件入门。

定义组件(MyButton.ets

ts 复制代码
@Component
struct MyButton {
  // 外部传入的文本
  @Prop text: string = "默认按钮";

  // 外部传入的点击回调
  @Prop onClick: () => void = () => {};

  // 内部状态:是否被点击过
  @State clicked: boolean = false;

  build() {
    Button(this.clicked ? "已点击: " + this.text : this.text)
      .width('80%')
      .height(50)
      .backgroundColor(this.clicked ? '#4CAF50' : '#2196F3')
      .fontColor('#fff')
      .borderRadius(10)
      .onClick(() => {
        this.clicked = true;   // 内部状态更新
        this.onClick();        // 触发外部回调
      })
  }
}

使用组件(Index.ets

ts 复制代码
@Entry
@Component
struct Index {
  build() {
    Column() {
      Text("自定义组件 Demo")
        .fontSize(20)
        .margin({ bottom: 20 })

      // 使用自定义按钮
      MyButton({
        text: "点我一下",
        onClick: () => {
          console.log("按钮被点击了!");
        }
      })
    }
    .width('100%')
    .height('100%')
    .alignItems(HorizontalAlign.Center)
    .justifyContent(FlexAlign.Center)
  }
}

运行效果:

  • 初始状态下,按钮显示"点我一下",背景蓝色。
  • 点击按钮后,文字变成"已点击: 点我一下",背景变成绿色。
  • 控制台会打印"按钮被点击了!"。

进阶场景应用

自定义组件真正的价值,在于它能适配各种业务需求。下面给你三个典型的场景案例。

场景一:带错误提示的输入框

表单类应用常见的需求:输入框输入错误时要提示用户。

ts 复制代码
@Component
struct ValidInput {
  @Prop placeholder: string = "请输入内容";
  @Prop validator: (value: string) => boolean = () => true;

  @State value: string = "";
  @State error: boolean = false;

  build() {
    Column() {
      TextInput({ placeholder: this.placeholder })
        .width('90%')
        .height(40)
        .border({ width: 1, color: this.error ? '#FF0000' : '#CCC' })
        .onChange((val: string) => {
          this.value = val;
          this.error = !this.validator(val);
        })

      if (this.error) {
        Text("输入格式不正确").fontColor('#FF0000').fontSize(12)
      }
    }
  }
}

使用:

ts 复制代码
ValidInput({
  placeholder: "请输入邮箱",
  validator: (val: string) => val.includes("@")
})

场景二:带动画的点赞按钮

很多社交类应用里,点赞按钮点一下会有动画效果。

ts 复制代码
@Component
struct LikeButton {
  @State liked: boolean = false;

  build() {
    Image(this.liked ? 'like_filled.png' : 'like_empty.png')
      .width(40)
      .height(40)
      .onClick(() => {
        animateTo({ duration: 300 }, () => {
          this.liked = !this.liked;
        })
      })
  }
}

点击时,图标会在 300 毫秒的动画中切换状态。

场景三:商品卡片组件

电商类应用常见的 UI,可以封装成可复用的组件。

ts 复制代码
@Component
struct ProductCard {
  @Prop title: string = "商品标题";
  @Prop price: string = "¥0.00";
  @Prop image: string = "default.png";

  build() {
    Column() {
      Image(this.image)
        .width(150).height(150)
      Text(this.title)
        .fontSize(16)
        .margin({ top: 5 })
      Text(this.price)
        .fontSize(14)
        .fontColor('#E91E63')
    }
    .borderRadius(10)
    .shadow({ radius: 5, color: '#aaa' })
    .padding(10)
  }
}

使用:

ts 复制代码
ProductCard({
  title: "鸿蒙定制T恤",
  price: "¥99",
  image: "tshirt.png"
})

常见问题 QA

Q1: 自定义组件和系统组件有什么区别? A: 系统组件是框架提供的基础能力,自定义组件是开发者封装的"组合能力"。你可以在自定义组件里用系统组件,也可以再嵌套别的自定义组件。

Q2: 如果父组件要修改子组件的状态怎么办? A: 用 @Link,父子组件可以共享状态变量。

Q3: 多层级传递数据很麻烦怎么办? A: 用 @Provide@Consume,可以跨层级传递状态,类似 Vue 的 provide/inject。

Q4: 自定义组件能不能写成库复用? A: 可以。你可以把常用组件封装成独立模块,在多个项目里复用。

总结

在鸿蒙开发中,自定义组件是提升开发效率和代码复用率的核心技能。 本文从最基础的"自定义按钮"入门,到进阶的"输入框校验""动画按钮""商品卡片",展示了自定义组件在实际场景中的灵活性。

记住几个关键点:

  • @Component 定义组件。
  • @Prop 接收父组件传值。
  • @State 处理内部状态。
  • 搭配 @Link@Provide@Consume,能处理更复杂的状态管理场景。

掌握这些后,你在鸿蒙开发里几乎可以封装任何 UI 组件,让项目既简洁又可维护。

相关推荐
zhanshuo3 小时前
HarmonyOS 推送通知开发实战:从权限申请到多场景应用的完整指南
harmonyos
奶糖不太甜11 小时前
鸿蒙开发组件问题:方法论与技术探索
harmonyos
鸿蒙小灰11 小时前
鸿蒙开发问题之网络请求库适配
网络协议·harmonyos
HarmonyOS_SDK15 小时前
汽车之家联合HarmonyOS SDK,深度构建鸿蒙生态体系
harmonyos
whysqwhw15 小时前
鸿蒙沉浸式
harmonyos
whysqwhw16 小时前
鸿蒙Stack使用
harmonyos
whysqwhw16 小时前
鸿蒙Flex使用
harmonyos
whysqwhw17 小时前
鸿蒙Row/Column使用
harmonyos