OpenHarmony 入门——ArkUI自定义组件的基础语法(一)

文章大纲

引言

在OpenHarmony 系统里ArkUI子系统显示的内容均为组件 ,由框架直接提供的称为系统组件,由开发者定义的称为自定义组件 。在进行 UI 界面开发时,通常不是简单的将系统组件进行组合使用,而是需要考虑代码可复用性、业务逻辑与UI分离,后续版本演进等因素。本文基本就是把官网文档重新整理了下。

一、自定义组件的基本语法

在OpenHarmony定义一个自定义组件语法很简单,通常来说只需要三步:

  • 定义一个被@Component 装饰器修饰的struct类型的自定义组件名
  • 在这个自定义组件的代码块内实现build函数
javascript 复制代码
@Component
struct MyComponent {
  build() {
  }
}

1、@Component 装饰器 和 @Entry 装饰器

@Component 装饰器像其他一些装饰器一样是华为的ArkTS语言(基于原生TypeScript的扩展)开发的机制,编译时会自动生成一些"胶水代码"完成一些相应的任务,比如说@State背后的原理就类似于观察者模式的应用,@Component装饰器仅能装饰struct关键字声明的数据结构。struct被@Component装饰后且实现了build方法描述UI结构后才具备组件化的能力,一个struct只能被一个@Component装饰。@Component可以接受一个可选的bool类型参数。

javascript 复制代码
//是否开启组件冻结。
@Entry
@Component({ freezeWhenInactive: true })
struct MyComponent {
}

并不是每一个组件都必须使用@Entry 装饰器,只有把这个自定义组件将作为UI页面的入口时才需要使用@Entry修饰。在单个UI页面中最多可以使用@Entry装饰一个自定义组件。@Entry可选参数:

从API version 10开始,@Entry可以接受一个可选的LocalStorage的参数或者一个可选的EntryOptions参数。

javascript 复制代码
class PropB {
 code: number;
 constructor(code: number) {
   this.code = code;
 }
}
// 创建新实例并使用给定对象初始化
let para: Record<string, number> = { 'PropA': 47 };
let storage: LocalStorage = new LocalStorage(para);
storage.setOrCreate('PropB', new PropB(50));

@Component
struct Child {
 // @LocalStorageLink变量装饰器与LocalStorage中的'PropA'属性建立双向绑定
 @LocalStorageLink('PropA') childLinkNumber: number = 1;
 // @LocalStorageLink变量装饰器与LocalStorage中的'PropB'属性建立双向绑定
 @LocalStorageLink('PropB') childLinkObject: PropB = new PropB(0);
 build() {
   Column() {
     Button(`Child from LocalStorage ${this.childLinkNumber}`) // 更改将同步至LocalStorage中的'PropA'以及Parent.parentLinkNumber
       .onClick(() => {
         this.childLinkNumber += 1;
       })
     Button(`Child from LocalStorage ${this.childLinkObject.code}`) // 更改将同步至LocalStorage中的'PropB'以及Parent.parentLinkObject.code
       .onClick(() => {
         this.childLinkObject.code += 1;
       })
   }
 }
}
// 使LocalStorage可从@Component组件访问
@Entry(storage)
@Component
struct CompA {
 // @LocalStorageLink变量装饰器与LocalStorage中的'PropA'属性建立双向绑定
 @LocalStorageLink('PropA') parentLinkNumber: number = 1;
 // @LocalStorageLink变量装饰器与LocalStorage中的'PropB'属性建立双向绑定
 @LocalStorageLink('PropB') parentLinkObject: PropB = new PropB(0);

 build() {
   Column({ space: 15 }) {
     Button(`Parent from LocalStorage ${this.parentLinkNumber}`) // initial value from LocalStorage will be 47, because 'PropA' initialized already
       .onClick(() => {
         this.parentLinkNumber += 1;
       })

     Button(`Parent from LocalStorage ${this.parentLinkObject.code}`) // initial value from LocalStorage will be 50, because 'PropB' initialized already
       .onClick(() => {
         this.parentLinkObject.code += 1;
       })
     // @Component子组件自动获得对CompA LocalStorage实例的访问权限。
     Child()
   }
 }
}

2、build函数

build()函数用于定义自定义组件的声明式UI描述,自定义组件必须定义build()函数。同时build函数里有一些约束规则:

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

  • 不允许声明本地变量或者本地代码块(作用域),反例如下。

    javascript 复制代码
    build() {
      // 反例:不允许声明本地变量
      let a: number = 1;
      //反例
      {
      }
    }
  • 不允许在UI描述里直接使用console.info,但允许在函数里使用。

  • 不允许调用没有用@Builder装饰的方法,允许系统组件的参数是TS方法的返回值

javascript 复制代码
@Component
struct ParentComponent {
  doSomeCalculations() {
  }
  calcTextValue(): string {
    return 'Hello World';
  }
  @Builder doSomeRender() {
    Text(`Hello World`)
  }
  build() {
    Column() {
      // 反例:不能调用没有用@Builder装饰的方法
      this.doSomeCalculations();
      // 正例:可以调用
      this.doSomeRender();
      // 正例:参数可以为调用TS方法的返回值
      Text(this.calcTextValue())
    }
  }
}
  • 不允许使用switch语法,如果需要使用条件判断,请使用if;也不允许使用三元表达式。
  • 不允许直接改变状态变量
javascript 复制代码
@Component
struct CompA {
  @State col1: Color = Color.Yellow;
  @State col2: Color = Color.Green;
  @State count: number = 1;
  build() {
    Column() {
      // 应避免直接在Text组件内改变count的值
      Text(`${this.count++}`)
        .width(50)
        .height(50)
        .fontColor(this.col1)
        .onClick(() => {
          this.col2 = Color.Red;
        })
    }
  }
}

3、@Reuseable

@Reusable装饰的自定义组件具备可复用能力,结合懒加载等机制可以提高UI的性能。

javascript 复制代码
@Reusable
@Component
struct MyComponent {
}

4、定义成员函数/变量

自定义组件除了必须要实现build()函数外,还可以实现其他成员函数,成员函数具有以下约束:

  • 自定义组件的成员函数为私有的,且不建议声明成静态函数。
  • 自定义组件可以包含成员变量,成员变量具有以下约束:

自定义组件的成员变量为私有的,且不建议声明成静态变量。

  • 自定义组件的成员变量本地初始化有些是可选的,有些是必选的。具体是否需要本地初始化,是否需要从- 父组件通过参数传递初始化子组件的成员变量,请参考状态管理。
javascript 复制代码
@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)
  }
}

二、自定义组件的使用

组件可以在其他自定义组件中的build()函数中多次创建,实现自定义组件的重用,自定义组件的构造函数也可以支持有参数的实现。

javascript 复制代码
@Entry
@Component
struct Parent {
  @State cnt: number = 0
  build() {
    Column() {
      Text(`${this.cnt}`)
      Son({ name:"crazymo" })
    }
  }
}

@Component
struct Son {
	private name: string;
	Son(str: string){
		this.name= str;
	}
  build() {
    Row() {
      Button('add')
        .width(80)
        })
    }
  }
}

如果在另外的文件中引用该自定义组件,需要使用export关键字导出,并在使用的页面import该自定义组件。

相关推荐
想你依然心痛1 小时前
HarmonyOS 6(API 23)实战:打造“空间交互式AR健身私教“——基于Face AR疲劳监测 + Body AR姿态识别的沉浸光感运动系统
ar·restful·harmonyos·悬浮导航·沉浸光感
xmdy58661 小时前
Flutter+开源鸿蒙实战|校园易生活Day2 第三方库批量集成+全局Toast提示+网络状态监听+首页轮播图+资讯卡片布局
flutter·开源·harmonyos
秋の本名1 小时前
DevEco Studio 版本演进揭秘:从3.0到5.0的分布式开发能力飞跃与智能体验革新
wpf·鸿蒙系统
前端不太难2 小时前
为什么说鸿蒙 App 是“状态系统”?
华为·状态模式·harmonyos
●VON2 小时前
猫咪专注 CatFocus 技术博客:一款鸿蒙原生自律计时工具的设计与实现
学习·华为·harmonyos·von·猫咪专注
小雨青年2 小时前
HarmonyOS 原生应用《会议随记 Pro》 V1.3 更新 支持折叠屏、2in1 和 Pura X Max 三形态适配
华为·harmonyos
xmdy586612 小时前
Flutter+开源鸿蒙实战|智联邻里Day9 系统权限适配+应用全局分享+缓存深度优化+版本更新弹窗
flutter·开源·harmonyos
李李李勃谦14 小时前
鸿蒙PC日志分析工具:实时监控、高亮显示与智能过滤
华为·harmonyos
maaath16 小时前
【maaath】Flutter for OpenHarmony 乐器学习应用开发实战
flutter·华为·harmonyos
李游Leo19 小时前
HarmonyOS AbilityStage 实战:别把启动参数散落在每个页面里
harmonyos