OpenHarmony ETS 掌握组件化这些装饰器写好界面事半功倍 原创 精华

陈浩南xxx
发布于 2022-4-24 14:18
浏览
3收藏

OpenHarmony ETS 掌握组件化这些装饰器写好界面事半功倍

水之积也不厚,则其负大舟也无力

前言:写这篇文章的目的性,是让新手了解几个装饰器的作用,知道如何更加的使得代码模块化,复用性更高,提升代码的阅读效率。

1,@Entry

  • @Entry装饰的@Component为页面的==总入口==,一个页面==有且仅有一个==@Entry
@Entry
@Component
struct Index {
  @State message: string = 'Hello World'

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
      }
      .width('100%')
    }
    .height('100%')
  }
}

Api9下的注册方式

OpenHarmony ETS 掌握组件化这些装饰器写好界面事半功倍-鸿蒙开发者社区OpenHarmony ETS 掌握组件化这些装饰器写好界面事半功倍-鸿蒙开发者社区

2,@Component

UI都是通过@Component声明来修饰,如下

  • 所有的UI都是由组件构成,组件的数据结构为struct
  • @Component==装饰struct==,使之成为自定义组件,
  • 自定义组件可以调用其他自定义组件和内置组件
  • 自定义组件内部==必须实现build方法==来描述UI结构
  • 禁止自定义构造函数

3,@Preview

  • ==单组件预览==,无视@Entry装饰器,仅预览被@Preview装饰的自定义组件
  • 在单个源文件中,==最多==可以使用**@Preview**==装饰一个自定义组件==
    我们在预览无Entry修饰的组件时

OpenHarmony ETS 掌握组件化这些装饰器写好界面事半功倍-鸿蒙开发者社区

于是我们可以用@Preview来预览效果

OpenHarmony ETS 掌握组件化这些装饰器写好界面事半功倍-鸿蒙开发者社区

4,@Builder

  • @Builder装饰器定义了一个如何==渲染自定义组件的方法==,语法和作用和build函数一致。

  • 通过@Builder装饰器可以在一个==自定义组件内==快速生成多个布局内容

这样的好处就是可以减少大量重复的代码,还能逻辑统一,一处修改多UI生效

@Entry
@Component
struct Index {
  @State message: string = 'Builder演示'
  @State isA: boolean= false
  @State isB: boolean= false
  @State isC: boolean= false
  @State isD: boolean= false

  /* 方法内有组件,需要加@Builder装饰 */
  @Builder myBuilder(str: string, state: boolean, click: () => void) {

    Row() {
      Text(str + ":" + state)
        .fontSize(24).margin({ right: 20 })

      Button('开关').fontSize(24).onClick(() => {
        click()
      })
    }
  }

  build() {
    Row() {
      Column() {
        Text(this.message)
          .fontSize(24)
          .fontWeight(FontWeight.Bold).margin({ bottom: 20 })

        this.myBuilder('A', this.isA, () => {
          this.isA = !this.isA
        })

        this.myBuilder('B', this.isB, () => {
          this.isB = !this.isB
        })

        this.myBuilder('C', this.isC, () => {
          this.isC = !this.isC
        })

        this.myBuilder('D', this.isD, () => {
          this.isD = !this.isD
        })

      }
      .width('100%')
    }
    .height('100%')
  }
}

OpenHarmony ETS 掌握组件化这些装饰器写好界面事半功倍-鸿蒙开发者社区

5,@Extend

  • ==对内置组件进行二次封装==

  • @Extend装饰器不能用在自定义组件struct定义框内

    模拟器测试报错,理论上是可以支持的

    这样的优点可以减少对内置组件的重复设置,可以封装在一个方法内

@Extend(Text) function fancy (size: number, color: ResourceColor) {
  .fontSize(size)
  .fontColor(color)
}

@Entry
@Component
struct Index {
      @State message: string = 'Extend演示'
    
    build() {
        Column() {
             Text(this.message)
             .fancy(24, Color.Blue)
        }
    }
}

6,@CustomDialog

  • 用于装饰自定义弹窗。
@CustomDialog
struct CustomDialogExample {
  controller: CustomDialogController
  cancel: () => void
  confirm: () => void

  build() {
    Column() {
      Text('自定义弹窗').fontSize(20).margin({ top: 10, bottom: 10 })
      Image($r('app.media.icon')).width(80).height(80)
      Text('你确认要这样选择吗?').fontSize(16).margin({ top: 10, bottom: 10 })
      Flex({ justifyContent: FlexAlign.SpaceAround }) {
        Button('否')
          .onClick(() => {
            this.controller.close()
            this.cancel()
          }).backgroundColor(0xffffff).fontColor(Color.Black)
        Button('是')
          .onClick(() => {
            this.controller.close()
            this.confirm()
          }).backgroundColor(0xffffff).fontColor(Color.Red)
      }.margin({ bottom: 10 })
    }
  }
}

@Entry
@Component
struct CustomDialogUser {
  @State text: string= ""
  dialogController: CustomDialogController = new CustomDialogController({
    builder: CustomDialogExample({ cancel: this.onCancel, confirm: this.onAccept }),
    cancel: this.existApp,
    autoCancel: true
  })

  onCancel() {
    console.info('Callback when the first button is clicked')
    this.text = '用户点击了取消'
  }

  onAccept() {
    this.text = '用户点击了确认'
    console.info('Callback when the second button is clicked')
  }

  existApp() {
    console.info('Click the callback in the blank area')
    this.text = '用户点击了空白处'
  }

  build() {
    Column() {

      Text(this.text).fontSize(24).margin({ top: 10 })

      Button('打开弹窗').fontSize(24)
        .onClick(() => {
          this.dialogController.open()
        })
    }.width('100%').margin({ top: 10 })
  }
}

OpenHarmony ETS 掌握组件化这些装饰器写好界面事半功倍-鸿蒙开发者社区

注意:从效果看 @State修饰的变量,从@CustomDialog修饰的CustomDialogExample类,回调了该方法,但是它没有重新使得build刷新

原因不明(==评论区有答案==)

7,@BuilderParam

可以在局部样式相同,局部样式不同是复用

@Component
struct CustomContainer {
  title: string;
  subTitle: string;
  @BuilderParam content: () => any

  build() {
    Column() {
      Text(this.title).fontSize(24).fontColor('#FF0000')
      Text(this.subTitle).fontSize(18).fontColor('#0D9FFB')

      this.content()
    }
  }
}

@Entry
@Component
export struct MainPage {
  build() {
    Column() {
      Text('@BuilderParam演示')
        .fontSize(24).margin({ top: 20 })

      Column() {
        CustomContainer({ title: '标题1', subTitle: '内容1' }) {
          Row() {
            Text('图文结合').fontSize(18)
            Image($r('app.media.app_icon')).width(30).height(30)
          }
        }
      }.margin({ top: 20 })

      Column() {
        CustomContainer({ title: '标题2', subTitle: '内容2' }) {
          Row() {
            Text('其他样式').fontSize(18)
            Button('点击').fontSize(20)
          }
        }
      }.margin({ top: 20 })


    }
    .height('100%')
    .width('100%')
  }
}

OpenHarmony ETS 掌握组件化这些装饰器写好界面事半功倍-鸿蒙开发者社区

8,@Styles

  • @Styles装饰的方法不能带参数

  • 组件内@Styles装饰的方法可以有多个

    多个相同属性可以利用此装饰器封装

@Entry
@Component
struct Stylesdemo {
  @State message: string = 'Hello World'

  @Styles backgroundRed(){
    .backgroundColor(Color.Red)

  }

  @Styles size100(){
    .width(100)
    .height(100)
  }

  build() {
    Row() {
      Column() {
        Text(this.message)
          .backgroundRed()
          .fontSize(50)
          .fontWeight(FontWeight.Bold)

        Image($r('app.media.app_icon')).size100()
      }
      .width('100%')
    }
    .height('100%')
  }
}

OpenHarmony ETS 掌握组件化这些装饰器写好界面事半功倍-鸿蒙开发者社区

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
已于2022-4-25 14:49:30修改
5
收藏 3
回复
举报
3条回复
按时间正序
/
按时间倒序
如此之白
如此之白

没有刷新是this指向问题

这样写就可以了

@State text: string= ""
  dialogController: CustomDialogController = new CustomDialogController({
    builder: CustomDialogExample({ cancel: this.onCancel.bind(this), confirm: this.onAccept.bind(this) }),
    cancel: this.existApp.bind(this),
    autoCancel: true
  })
回复
2022-4-24 16:27:55
陈浩南xxx
陈浩南xxx 回复了 如此之白
没有刷新是this指向问题 这样写就可以了 @State text: string= "" dialogController: CustomDialogController = new CustomDialogController({ builder: CustomDialogExample({ cancel: this.onCancel.bind(this), confirm: this.onAccept.bind(this) }), cancel: this.existApp.bind(this), autoCancel: true })

果然可以,谢谢大佬指点; 想问下:bind(this)这个this是指的谁?

回复
2022-4-24 16:54:49
如此之白
如此之白 回复了 陈浩南xxx
果然可以,谢谢大佬指点; 想问下:bind(this)这个this是指的谁?

指向这个组件CustomDialogUser自己

其实等同于

cancel: ()=>{
    this.onCancel()
}

cancel传递一个普通函数的时候,这个函数的上下文其实已经改变了,为了保证上下文还是CustomDialogUser,需要指定this的指向。

可以看看es6的箭头函数

https://www.liaoxuefeng.com/wiki/1022910821149312/1031549578462080

 

回复
2022-4-24 17:17:56
回复
    相关推荐