Skip to content

鸿蒙开发--语法和生命周期

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

自定义组件

重点

  • 状态

  • 组件化

定义界面状态

按照声明式 UI 的开发范式,⾸先需要分析和定义⻚⾯的各种状态,并声明相应的状态变量⽤于表示不同的状态。

当前案例中,界⾯共有两个状态,分别是开灯关灯状态,所以我们可以使⽤⼀个 boolean 类型的变量来表示这两个状态, true 表示开灯, false 表示关灯。如下:

bash

@State isOn:boolean = false;

说明: @State用于声明该变量为状态变量

改变状态

当 isOn 为 true 就是开灯

当 isOn 为 false 就是关灯

当状态数据改变的时候,界面就会自动更新

状态

组件化

在鸿蒙开发中,组件是构成界⾯的最⼩单元,我们所看到的界⾯,都是由众多组件组合⽽成的,所以编写界⾯其实就是组合组件的过程,ArkTS 提供了很多的内置组件,例如: Text 、 Button 、 Image 等等;并且 ArkTS 还⽀持⾃定义组件,让开发者可根据具体需求⾃定义组件中的内容。

开关灯例子代码

  • 在这个例子中 通过改变 isOn 状态来改变图片
js

@Entry
@Component
struct Light {
  @State isOn: boolean = false;

  build() {
    Column({ space: 20 }) {
      Row() {
        /* 开关 */
        if (!this.isOn) {
          Image('pages/light/imgs/img_dark.png').width(300).height(300)
        } else {
          Image('pages/light/imgs/img_light.png').width(300).height(300)
        }
      }

      Row({ space: 20 }) {
        Button('开灯').onClick(() => {
          this.isOn = true;
        }).width(100)
        Button('关灯').onClick(() => {
          this.isOn = false;
        }).width(100)
      }
    }.height('100%').width('100%').justifyContent(FlexAlign.Center)
  }
}

声明组件的完整语法

状态

组件参数

如果组件的定义包含参数,可在组件名称后⾯的 () 中配置相应参数。各组件⽀持的参数,可查看 API ⽂档,查看⽅式如下

  • ⾸先将⿏标在相应组件悬停

状态

点击 Show in API Reference ,就会弹出 API ⽂档

状态

  • 子组件

如果组件支持子组件配置,可在()后的{}添加子组件,若不支持子组件,则不需要{}

  • 属性方法

属性方法用于配置组件的样式和其他属性,可以在组件声明的末尾进行链式调用。各组件支持的属性可以查看 API ⽂档

除去每个组件的专有属性,还有各组件都能配置的通用属性,通用属性也可以通过 api 文档查看

状态

  • 事件方法

事件方法用于为组件绑定交互事件,可以在组件声明的末尾进行链式调用.各组件的支持事件可以查看 API 文档

除去每隔组件的专有事件,还有各个组件都支持的通用事件,通用事件也可以通过 api 文档查看

状态

自定义组件

除去系统预置的组件外,ArkTs 还支持自定义组件。使用自定义组件,可以使代码的机构更加清晰,并且提高代码的复用性

语法说明

状态

各部分语法说明

  • struct 关键字

structArkTs新增的用于自定义组件或者自定义弹窗的关键字.其声明的数据结构和 Ts 的类十分相似。可包含属性和方法

  • build 方法

build()方法用于声明自定义组件的 UI 结构

  • 组件属性

组件属性可用作自定义组件的参数,使得自定义组件更为通用

  • @Component 装饰器

@Component装饰器用于装饰struct关键字声明的数据结构。struct@Component装饰后才具备组件化的能力

注意: 装饰器是 TS 一种特殊的语法,用于装饰类,方法,属性,用于修改或者扩展其原有的行为

INFO

在学完自定义组件的语法之后,我们会发现 前文案例中的每个页面实际上都是一个自定义组件

但是和自定义组件的语法相比,前边的案例还多出一个@Entry装饰器,那@Entry的作用是什么呢?

  • @Entry

在鸿蒙应用中,每个页面都是由一些列组件组合形成的。并且这些组件都逐层嵌套,因此最终形成了一个组件树

状态

我们前边所编写的每个页面就相当于组件树的根节点,而@Entry装饰器的作用就是标识该组件为组件树的根节点,也就是页面的入口组件

案例赏析

  • 自定义组件

新建一个 CustomButton.ets 文件

INFO

  1. 图片路径必须是 pages 开头

  2. 自定义组件传递参数必须放在 build 的外面

  3. 传递参数通过对象来传递 调用的时候必须加上 this,但是他前面不用加@State

bash

@Component
export struct SwitchButton {
  color:Color = Color.Blue;
  build() {
    Button(){
      Image("pages/light/imgs/icon_switch.png")
    }.type(ButtonType.Circle).backgroundColor(this.color).height(45).width(45)
  }
}
  • 调用的时候

INFO

  1. 引入的时候必须写在第一行

  2. 调用的地址写相对路径

  3. 参数传递必须通过对象传递

bash
import {SwitchButton} from './components/CustomButton'
@Entry
@Component
struct Light {
  @State isOn: boolean = false;

  build() {
    Column({ space: 20 }) {
      Row() {
        /* 开关 */
        if (!this.isOn) {
          Image('pages/light/imgs/img_dark.png').width(300).height(300)
        } else {
          Image('pages/light/imgs/img_light.png').width(300).height(300)
        }
      }

      Row({ space: 20 }) {
        SwitchButton({color:Color.Red}).onClick(()=>{
          this.isOn = false;
        })

        SwitchButton({color:Color.Green}).onClick(()=>{
          this.isOn = true;
        })
      }
    }.height('100%').width('100%').justifyContent(FlexAlign.Center)
  }
}

组件生命周期

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

组件的生命周期

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

  • aboutToAppear:函数在创建自定义组件的新实例后,在执行其 build() 函数之前执行。允许在该函数中改变状态变量,更改将在后续执行 build() 函数中生效。

  • aboutToDisappear:函数在自定义组件析构消耗之前执行。不允许在该函数中改变状态变量,特别是 @Link 变量的修改可能会导致应用程序行为不稳定。

页面的生命周期

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

  • onPageShow:页面显示时触发一次,包括路由过程、应用进入前后台等场景,仅 @Entry 修饰的自定义组件生效。

  • onPageHide:页面消失时触发一次,包括路由过程、应用进入前后台等场景,仅 @Entry 修饰的自定义组件生效。

  • onBackPress:当用户点击返回按钮时触发,仅 @Entry 修饰的自定义组件生效。该方法返回 boolean 类型的值,说明如下:

  1. 返回 true 表示页面自己处理返回逻辑, 不进行页面路由。

  2. 返回 false 表示使用默认的返回逻辑。

  3. 不返回值会作为 false 处理。

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

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

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

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

再按一次,退出应用

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

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

bash

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;
  }
}

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

图片

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

  • 可组合:允许开发人员组合使用内置组件和其他组件,以及公共属性和方法。

  • 可重用:可以被其他组件重用,并作为不同的实例在不同的父组件或容器中使用;

  • 有生命周期:生命周期的回调方法可以在组件中配置,用于业务逻辑处理;

  • 数据驱动更新:可以由状态数据驱动,实现 UI 自动更新