HarmonyOS鸿蒙Next中请教个组件封装的问题

HarmonyOS鸿蒙Next中请教个组件封装的问题

我想封装个通用的按钮组件,Button()相关的属性只能通过参数传递进来吗?比如我外部有的地方需要设置按钮高度有的不需要,就只能通过下边代码里的buttonHeight参数传递吗?要想控制Button()的其它属性都需要挨个写参数?

```typescript
[@ComponentV2](/user/ComponentV2)
export struct PrimaryTextButton {
  [@Require](/user/Require) [@Param](/user/Param) text: string | Resource
  [@Event](/user/Event) onButtonClick(): void | Promise<void>
  [@Param](/user/Param) buttonHeight?: Length = '78lpx'
  [@Param](/user/Param) buttonPadding?: Padding = { left: '50lpx', right: '50lpx' }
  [@Param](/user/Param) buttonEnabled: boolean = true
  private loading: boolean = false
  [@Local](/user/Local) private fontColor: ResourceColor = Color.White
  [@Local](/user/Local) private bgColor: ResourceColor = appTheme.colors.primary
  [@Local](/user/Local) private showLoading: boolean = false

  build() {
    Button() {
      Row() {
        Text(this.text)
          .fontSize('28lpx')
          .fontColor(this.fontColor)
        if (this.showLoading) {
          LoadingProgress()
            .width('50lpx')
            .height('50lpx')
        }
      }
    }
    .height(this.buttonHeight)
    .backgroundColor(this.bgColor)
    .padding(this.buttonPadding ?? {})
    .enabled(this.buttonEnabled && !this.loading)
    .onClick(() => {
      if (!this.buttonEnabled || this.loading) {
        return
      }
      const r: void | Promise<void> = this.onButtonClick()
      if (r instanceof Promise) {
        this.loading = true
        this.checkAnimation()
        r.finally(() => setTimeout(() => {
          this.loading = false
          this.checkAnimation()
        }))
      }
    })
  }

  [@Monitor](/user/Monitor)('buttonEnabled')
  private enableStateChanged(_: IMonitor) {
    this.checkAnimation()
  }

  private checkAnimation() {
    const b = this.buttonEnabled && !this.loading
    this.getUIContext()?.animateTo({
      duration: 250,
      curve: Curve.Friction
    }, () => {
      this.fontColor = b ? Color.White : appTheme.colors.disabledText
      this.bgColor = b ? appTheme.colors.primary : appTheme.colors.disabledBg
      this.showLoading = this.loading
    })
  }
}

更多关于HarmonyOS鸿蒙Next中请教个组件封装的问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html

8 回复

@Component struct MyButton { buttonHeight: number; // 控制按钮高度的参数 buttonText: string; // 控制按钮文本的参数

build() {
    Button(this.buttonText)
    .height(this.buttonHeight)
    .width(100)
    .backgroundColor('f00')
    .onClick(() => {
        console.log('Button onClick');
    })
    .onTouch((event) => {
        console.log('Button onTouch');
        event.stopPropagation();
    })
}

}

更多关于HarmonyOS鸿蒙Next中请教个组件封装的问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


我想给按钮加个通用的loading状态,这个应该是根据onClick返回的Promise来判断loading,属性修改器好像不行?

可以试试用@Extend来 进行传参

[@Extend](/user/Extend)(Button) function fancy (widths?:number,heights?:number,bgcol?:string) {
  .width(widths)
  .backgroundColor(bgcol)
  .height(heights)
}
Button()
  .fancy(undefined,100,'#666')

@Extend好像不支持跨文件使用?而且我想要封装一个带loading的按钮,用这个好像也不行,

那你试试这个三方库看可不可以满足你的需求:[@ibestservices/ibest-ui](https://ibestui.ibestservices.com/components/button/#button-按钮)

在HarmonyOS Next中封装组件需使用ArkUI框架。组件封装主要涉及三种文件:.ets(UI结构)、.json(组件配置)、.style(样式)。通过@Component装饰器声明自定义组件,使用@Builder构建可复用UI片段,@Styles定义可复用样式。组件通信采用Prop/State机制,父组件通过Prop传递数据,子组件使用@Link@ObjectLink实现双向绑定。生命周期管理提供aboutToAppear和aboutToDisappear回调。封装时需注意组件独立性,避免对外部状态直接依赖。

在HarmonyOS Next中封装通用按钮组件时,确实可以通过参数传递Button属性,但这不是唯一方式。更优雅的做法是使用Builder模式或属性代理:

  1. 使用@BuilderParam接收外部样式:
@ComponentV2
export struct PrimaryTextButton {
  [@BuilderParam](/user/BuilderParam) buttonStyle?: (button: Button) => void

  build() {
    Button() {
      // 内容
    }
    .apply(this.buttonStyle) // 应用外部传入的样式
  }
}

// 使用时:
PrimaryTextButton({
  buttonStyle: (btn) => {
    btn.height('100lpx').width('200lpx')
  }
})
  1. 使用扩展方法复用样式:
function primaryStyle(button: Button): Button {
  return button.height('78lpx').padding({left:'50lpx',right:'50lpx'})
}

// 在组件中直接调用
Button().apply(primaryStyle)
  1. 对于必须参数建议保留@Param,可选样式建议使用BuilderParam。这样既保证了核心功能的可控性,又提供了样式定制的灵活性。

这种模式比逐个参数传递更灵活,也更容易维护。Builder模式特别适合需要高度定制样式的组件封装场景。

回到顶部