# 9.1:语法和生命周期

组件是 OpenHarmony 页面最小显示单元,一个页面可由多个组件组合而成,也可只由一个组件组合而成,这些组件可以是ArkUI开发框架自带系统组件,比如 TextButton 等,也可以是自定义组件,本节笔者简单介绍一下自定义组件的语法规范。

# 9.1.1:定义组件

自定义一个组件,首先要定义好名称,尽量做到见名知意,比如定义一个标题栏组件,笔者把它命名为 TitleBar ,为了让系统知道这是一个组件,需要使用 @Component 修饰符和 struct 关键字修饰,格式:【@Component struct + 组件名称】,如下所示:

@Component struct TitleBar {
  build() {
    // 省略
  }
}

@Entry @Component struct Index {
  build() {
    // 省略
  }
}
1
2
3
4
5
6
7
8
9
10
11
  • struct:表示 TitleBar 是一个结构体,使用 struct 关键字必须实现 build() 方法,否则编译器报错:Require build function for struct
  • @Component:表示 TitleBar 这个结构体具有组件化的能力,也就是说它可以成为一个独立的组件。
  • @Entry:表示当前组件是页面的总入口,简单理解就是页面的根节点,一个页面有且仅有一个 @Entry 修饰符,只有被 @Entry 修饰的组件或者子组件才会在页面上显示。

📢:自定义组件禁止添加构造函数,否则编译器报错。

# 9.1.2:刷新组件

使用 struct 关键字修饰完 TitleBar 后必须实现 build() 方法,该方法满足 Builder 构造器接口定义,用于定义组件的声明式 UI 描述,在组件创建或者组件内 @State 修饰的变量更新时系统都会自动调用 build() 方法。

@Component struct TitleBar {

  @State count: number = 0;

  build() {
    Flex() {
      Text("index:" + this.number)
      // ……
    }
    .width('100%')
    .height('100%')
    .backgroundColor("#aabbcc")
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

上述样例中当 count 的值发生了变化,系统会自动调用 build() 方法更新相关属性值,实现 UI 刷新的目的。

# 9.1.3:导出组件

自定义完组件后,提供给外界使用时还要允许该组件可以导出,导出组件使用关键字 export ,如下所示:

@Component export struct TitleBar { // 使用export关键字导出TitleBar组件

  build() {
    Flex() {
    }
    .width('100%')
    .height('100%')
    .backgroundColor("#aabbcc")
  }
}
1
2
3
4
5
6
7
8
9
10

# 9.1.4:使用组件

使用自定义组件用关键字 import 导入即可,例如使用自定义组件 TibleBar ,导入如下所示:

import {TitleBar} from "../../common/widgets/titlebar" // 导入TitleBar

@Entry @Component struct Index {

  build() {
    Column() {
      TitleBar({titleBarAttribute: {                   // 使用TitleBar
                                                       // 添加相关属性
      }})

    }
    .padding({bottom: 5})
    .backgroundColor('#010101')
    .width('100%')
    .height('100%')
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

自定义组件的使用和系统组件使用无差别,直接引用即可。

# 9.1.5:组件生命周期

ArkUI开发框架赋予了组件独有的生命周期方法,对于系统组件来讲,生命周期方法是 onAppearonDisAppear ,笔者在第三章 第 2 节 讲过,这里不再叙述了,这里只讲述一下自定义组件的生命周期。

  • 组件的生命周期

    使用 @Component 修饰的组件,ArkUI开发框架会自动为其赋予私有的生命周期方法 aboutToAppear()aboutToDisappear() ,它们用于通知开发者该自定义组件的生命周的变更。

    • aboutToAppear:函数在创建自定义组件的新实例后,在执行其 build() 函数之前执行。允许在该函数中改变状态变量,更改将在后续执行 build() 函数中生效。
    • aboutToDisappear:函数在自定义组件析构消耗之前执行。不允许在该函数中改变状态变量,特别是 @Link 变量的修改可能会导致应用程序行为不稳定。
  • 页面的生命周期

    页面本质上也是一个组件,只是页面对于组件来讲多了一个修饰符 @Entry,该修饰符表示当前组件是一个页面,它需要在 config.json 中做配置,页面除了具有组件的生命周期外,它还有自己独有的生命周期方法:

    • onPageShow:页面显示时触发一次,包括路由过程、应用进入前后台等场景,仅 @Entry 修饰的自定义组件生效。
    • onPageHide:页面消失时触发一次,包括路由过程、应用进入前后台等场景,仅 @Entry 修饰的自定义组件生效。
    • onBackPress:当用户点击返回按钮时触发,仅 @Entry 修饰的自定义组件生效。该方法返回 boolean 类型的值,说明如下:
      • 返回 true 表示页面自己处理返回逻辑, 不进行页面路由。
      • 返回 false 表示使用默认的返回逻辑。
      • 不返回值会作为 false 处理。

组件生命周期制作表格对比说明如下:

函数名 描述
onAppear 系统组件独有的方法,组件从组件树上挂载的回调。
onDisAppear 系统组件独有的方法,组件从组件树上卸载的回到。
aboutToAppear 函数在创建自定义组件的新实例后,在执行其 build() 函数之前执行。允许在该函数中改变状态变量,更改将在后续执行 build() 函数中生效。
aboutToDisappear 函数在自定义组件析构消耗之前执行。不允许在该函数中改变状态变量,特别是 @Link 变量的修改可能会导致应用程序行为不稳定。
onPageShow 页面显示时触发该回调,包括路由过程、应用进入前后台等场景。仅 @Entry 修饰的自定义组件生效。
onPageHide 页面消失时触发该回调,包括路由过程、应用进入前后台等场景。仅 @Entry 修饰的自定义组件生效。
onBackPress 当用户点击返回按钮时触发,该方法返回 boolean 类型,true:表示页面自己处理返回逻辑, 不进行页面路由。false:表示使用默认的返回逻辑。不返回值会作为 false 处理。仅 @Entry 修饰的自定义组件生效。

📢:这些回调函数是私有的,在运行时由开发框架在特定的时间进行调用,不能从应用程序中手动调用这些回调函数。

📢:允许在生命周期函数中使用 Promise 和异步回调函数,比如网络资源获取,定时器设置等;不允许在生命周期函数中使用 async await

# 9.1.6:再按一次,退出应用

我们在使用第三方 APP 的时候会遇见点击返回键提示再按一次退出应用的场景,比如在短时间内不按,就不会退出 APP 达到留住用户的目的,接下来我们实现这个再按一次退出应用的例子。

根据页面生命周期的方法可知,点击返回键的时候会调用 onBackPress() 方法,因此判断是否是第一次点击,如果是则返回 true 并给用户提示,如果不是则判断两次点击的时间间隔,若间间隔小于 2 秒,那么就直接退出 APP ,否则给用户提示,本样例复用第二章的测试代码,如下所示:

import app from '@system.app';

@Entry @Component struct Index {

  private lastExitTime: number = -1;               // 记录点击时间

  @State count: number = 0;                        // 状态数据

  build() {
    Stack({alignContent: Alignment.BottomEnd}) {   // 堆叠式布局
      Text(this.count.toString())                  // 显示文本
        .fontSize(50)                              // 文字大小
        .textAlign(TextAlign.Center)               // 居中对齐
        .size({width: '100%', height: '100%'})     // 控件大小

      Button('+')                                  // 显示一个+按钮
        .size({width: 80, height: 80})             // 按钮大小
        .fontSize(50)                              // 按钮文字大小
        .onClick(() => {                           // 按钮点击事件
          this.count++;                            // count累加,触发build()方法回调
        })
        .margin(50)
    }
    .width('100%')
    .height('100%')
  }

  onBackPress() {
    if (-1 == this.lastExitTime) {                 // 第一次点击返回键,提示toast
      this.lastExitTime = new Date().getTime();
      prompt.showToast({
        message: "再按一次退出应用"
      })
      return true;
    } else {
      let currentTime = new Date().getTime();
      if(currentTime - this.lastExitTime > 2000) { // 时间大于2000提示
        prompt.showToast({
          message: "再按一次退出应用"
        })
        this.lastExitTime = currentTime;
        return true;
      } else {                                     // 2秒内点击,退出APP
        app.terminate();
      }
    }
    return false;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

样例运行结果如下图所示:

9_1_6_1

以上就是自定义一个组件需要遵循的语法规范,自定义组件具有以下特点:

  • 可组合:允许开发人员组合使用内置组件和其他组件,以及公共属性和方法。
  • 可重用:可以被其他组件重用,并作为不同的实例在不同的父组件或容器中使用;
  • 有生命周期:生命周期的回调方法可以在组件中配置,用于业务逻辑处理;
  • 数据驱动更新:可以由状态数据驱动,实现UI自动更新。
(adsbygoogle = window.adsbygoogle || []).push({});
请作者喝杯咖啡

津公网安备 12011402001367号

津ICP备2020008934号-2