# 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

自定义组件的使用和系统组件使用无差别,直接引用即可,如果自定义组件需要传值,方式是在组件的构造方法中传递一个匿名对象 {} 进去,且该匿名对象中的属性名称和类型要和自定义组件中的属性保持一致,具体实现原理读者可参考第十九章第 3 小节:自定义组件传值浅析

# 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

中央网信办互联网违法和不良信息举报中心

天津市互联网违法和不良信息举报中心