鸿蒙2:自定义组件

鸿蒙:自定义组件

@Component
struct HelloComponent {
  @State message: string = 'Hello, World!';

  build() {
    // HelloComponent自定义组件组合系统组件Row和Text
    Row() {
      Text(this.message)
        .onClick(() => {
          // 状态变量message的改变驱动UI刷新,UI从'Hello, World!'刷新为'Hello, ArkUI!'
          this.message = 'Hello, ArkUI!';
        })
    }
  }
}

class HelloComponentParam {
  message: string = ""
}

@Entry
@Component
struct ParentComponent {
  param: HelloComponentParam = {
    message: 'Hello, World!'
  }

  build() {
    Column() {
      Text('ArkUI message')
      HelloComponent(this.param);
      Divider()
      HelloComponent(this.param);
    }
  }
}
1.自定义组件的基本结构
  • @Entry:@Entry装饰的自定义组件将作为UI页面的入口。
  • struct:自定义组件基于struct实现,struct + 自定义组件名 + {...}的组合构成自定义组件,不能有继承关系。对于struct的实例化,可以省略new。
  • @Component:@Component装饰器仅能装饰struct关键字声明的数据结构,struct被@Component装饰后具备组件化的能力,需要实现build方法描述UI
  • build()函数:build()函数用于定义自定义组件的声明式UI描述,自定义组件必须定义build()函数。
  • @Reusable:@Reusable装饰的自定义组件具备可复用能力
@Entry({ routeName : 'myPage' })
@Reusable
@Component
struct MyComponent {
  build() {
  }
}

2.成员函数/变量

自定义组件的成员函数为私有的,且不建议声明成静态函数。
下面的示例代码将父组件中的函数传递给子组件,并在子组件中调用。

@Entry
@Component
struct Parent {
  @State cnt: number = 0
  submit: () => void = () => {
    this.cnt++;
  }

  build() {
    Column() {
      Text(`${this.cnt}`)
      Son({ submitArrow: this.submit })
    }
  }
}

@Component
struct Son {
  submitArrow?: () => void

  build() {
    Row() {
      Button('add')
        .width(80)
        .onClick(() => {
          if (this.submitArrow) {
            this.submitArrow()
          }
        })
    }
    .justifyContent(FlexAlign.SpaceBetween)
    .height(56)
  }
}

3.build()函数

所有声明在build()函数的语句,我们统称为UI描述,UI描述需要遵循以下规则:

  • @Entry装饰的自定义组件,其build()函数下的根节点唯一且必要,且必须为容器组件,其中ForEach禁止作为根节点。
  • @Component装饰的自定义组件,其build()函数下的根节点唯一且必要,可以为非容器组件,其中ForEach禁止作为根节点。
@Entry
@Component
struct MyComponent {
  build() {
    // 根节点唯一且必要,必须为容器组件
    Row() {
      ChildComponent() 
    }
  }
}

@Component
struct ChildComponent {
  build() {
    // 根节点唯一且必要,可为非容器组件
    Image('test.jpg')
  }
}
  • 不允许声明本地变量,反例如下。
  • 不允许在UI描述里直接使用console.info,但允许在方法或者函数里使用,反例如下
  • 不允许创建本地的作用域,反例如下。
  • 不允许调用没有用@Builder装饰的方法,允许系统组件的参数是TS方法的返回值。
  • 不允许使用switch语法,如果需要使用条件判断,请使用if。示例如下。
  • 不允许使用表达式,反例如下。
  • 不允许直接改变状态变量,会造成循环渲染的风险。
build() {
  // 反例1:不允许声明本地变量
  let a: number = 1;
  // 反例2:不允许console.info
  console.info('print debug log');
 // 反例3:不允许本地作用域
  {
    ...
  }
}
@Component
struct ParentComponent {
  @State count: number = 1;
  doSomeCalculations() {
  }

  calcTextValue(): string {
    return 'Hello World';
  }

  @Builder doSomeRender() {
    Text(`Hello World`)
  }
  build() {
    Column() {
      // 反例4:不能调用没有用@Builder装饰的方法
      this.doSomeCalculations();
      // 正例:可以调用
      this.doSomeRender();
      // 正例:参数可以为调用TS方法的返回值
      Text(this.calcTextValue())

  // 反例5:不允许使用switch语法
    switch (expression) {
      case 1:
        Text('...')
        break;
      case 2:
        Image('...')
        break;
      default:
        Text('...')
        break;
    }
    // 正例:使用if
    if(expression == 1) {
      Text('...')
    } else if(expression == 2) {
      Image('...')
    } else {
      Text('...')
    }
   // 反例6:不允许使用表达式
    (this.aVar > 10) ? Text('...') : Image('...')
 //反例7: 应避免直接在Text组件内改变count的值
      Text(`${this.count++}`)
  }
// 反例 8:
@State arr : Array<...> = [ ... ];
ForEach(this.arr.sort().filter(...), 
  item => { 
  ...
})
// 正确的执行方式为:filter返回一个新数组,后面的sort方法才不会改变原数组this.arr
ForEach(this.arr.filter(...).sort(), 
  item => { 
  ...
})
}

4.自定义组件通用样式
  • 自定义组件通过“.”链式调用的形式设置通用样式。一行一个
@Component
struct MyComponent2 {
  build() {
    Button(`Hello World`)
  }
}

@Entry
@Component
struct MyComponent {
  build() {
    Row() {
      MyComponent2()
        .width(200)
        .height(300)
        .backgroundColor(Color.Red)
    }
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容