ArkTS基础学习笔记

ArkTS基础

基于:HarmonyOS开发者3.1/4.0版本配套的开发者文档,对应API能力级别为API 9 Release

基本语法

基本语法概述

在这里插入图片描述

  • 装饰器:用于修饰类、结构、方法以及变量,并赋予其特殊含义
  • UI描述:以声明的方式来描述UI的结构,可组合其他组件,如上述被@Component装饰的struct Hello
  • 自定义组件:可复用的UI单元,可组合其他组件
  • 系统组件:ArkUI框架中默认内置的基础和容器组件,可直接调用
  • 属性方法:组件可以通过链式调用配置多项属性
  • 事件方法:组件可以通过链式调用设置多个事件的相应逻辑

声明式UI描述

ARkTS以声明方式组合和扩展组件来描述应用程序的UI,还提供了基本的属性、事件、子组件配置方法

创建组件

创建组件包含有参数和无参数两种方式(具体根据组件的构造方法)

如果组件的接口定义没有包含必选构造参数,则组件后面的()不需要配置任何内容,如:

Column() {
  Text('item 1')
  Divider()
  Text('item 2')
}

如果组件的接口定义包含构造参数,可以在组件后面的()配置相应参数:

// string类型的参数
Text('test')
// $r形式引入应用资源,可应用于多语言场景
Text($r('app.string.title_value'))
// 无参数形式
Text()
// 变量或表达式也可以用于参数赋值,表达式返回的结果类型必须满足参数类型要求
Text(`count: ${this.count}`)
配置属性

属性方法以.链式调用的方式配置系统组件的样式和其他属性,建议每个属性方法单独写一行

// 配置Text组件字体的大小
Text('test')
  .fontSize(12)
// 配置组件的多个属性,还可以传入变量或者表达式
Image('test.jpg')
  .alt('error.jpg')    
  .width(this.count % 2 === 0 ? 100 : 200)    
  .height(this.offset + 100)
// 对于一些系统组件,ArkUI还为其预定义了一些枚举类型供调用
Text('hello')
  .fontSize(20)
  .fontColor(Color.Red)
  .fontWeight(FontWeight.Bold)
配置事件

事件方法以.链式调用的方式配置系统组件支持的事件,建议每个事件方法单独写一行

// 使用剪头函数配置组件的事件方法
Button('Click me')
  .onClick(() => {
    this.myText = 'ArkUI';
  })
// 使用匿名函数,要求使用bind,以确保函数中的this指向当前组件
Button('add counter')
  .onClick(function(){
    this.counter += 2;
  }.bind(this))
// 使用组件成员函数
myClickHandler(): void {
  this.counter += 2;
}
...
Button('add counter')
  .onClick(this.myClickHandler.bind(this))
配置子组件

如果组件支持子组件配置,则需要再尾随闭包{...}中为组件添加子组件的UI描述(组件嵌套)

Column() {
  Text('Hello')
    .fontSize(100)
  Divider()
  Text(this.myText)
    .fontSize(100)
    .fontColor(Color.Red)
}

自定义组件

自定义组件具有以下特点:

  • 可组合:允许组合使用系统组件及其属性和方法
  • 可重用:自定义组件可以被其他组件重用
  • 数据驱动UI更新:通过状态量的改变,来驱动UI的刷新
自定义组件的基本结构
  • struct:自定义组件基于struct实现,struct + 自定义组件名 + {…}的组合构成自定义组件,不能有继承关系
  • @Component:@Component装饰器仅能装饰struct关键字声明的数据结构。struct被@Component装饰后具备组件化的能力,需要实现build方法描述UI,一个struct只能被一个@Component装饰
  • build()函数:build()函数用于定义自定义组件的声明式UI描述,自定义组件必须定义build()函数
  • @Entry:@Entry装饰的自定义组件将作为UI页面的入口。在单个UI页面中,最多可以使用@Entry装饰一个自定义组件。@Entry可以接受一个可选的LocalStorage的参数

成员函数/变量

成员函数具有以下约束:

  • 不支持静态函数
  • 成员函数的访问始终是私有的

自定义组件的成员变量有以下约束:

  • 不支持静态成员变量
  • 所有成员变量都是私有的
  • 自定义组件的成员变量本地初始化有些是可选的,有些是必选的
@Component
struct MyComponent {
  private countDownFrom: number = 0;
  private color: Color = Color.Blue;

  build() {
  }
}

@Entry
@Component
struct ParentComponent {
  private someColor: Color = Color.Pink;

  build() {
    Column() {
      // 创建MyComponent实例,并将创建MyComponent成员变量countDownFrom初始化为10,将成员变量color初始化为this.someColor
      MyComponent({ countDownFrom: 10, color: this.someColor })
    }
  }
}

build()函数

所有声明在build函数的语言,统称为UI描述语言,需要遵循:

  • @Entry装饰的自定义组件,其build()函数下的根节点唯一且必要,且必须为容器组件,其中ForEach禁止作为根节点
  • @Component装饰的自定义组件,其build()函数下的根节点唯一且必要,可以为非容器组件,其中ForEach禁止作为根节点
  • 不允许声明本地变量
  • 不允许使用console.info
  • 不允许创建本地的作用域
  • 不允许调用除了被@Builder装饰的方法以外的方法
  • 不允许switch语法,如果需要使用条件判断,请使用if
  • 不允许使用表达式
自定义组件通用样式

自定义组件通过“.”链式调用的形式设置通用样式

设置样式时并不是直接设置给自定义组件的,相当于给自定义组件套一个不可见的容器,样式被设置给这个容器

生命周期

页面生命周期如下:

  • onPageShow:页面每次显示时触发
  • onPageHide:页面每次隐藏时触发一次
  • onBackPress:用户点击返回按钮时触发

组件生命周期:

  • aboutToAppear:组件即将出现时回调该接口(创建组件实例后调用build前)
  • aboutToDisappear:组件即将析构销毁时执行

自定义组件的创建和渲染流程

  1. 创建自定义组件
  2. 初始化自定义组件的成员变量
  3. 执行aboutToAppear
  4. 在首次渲染的时候,执行build,否则执行onPageShow

第4步会保存两个map:

  • 状态变量–>UI组件(包括ForEach和if)
  • UI组件–>此组件的更新函数

自定义组件的重新渲染

当事件句柄被触发改变了状态变量时,或者LocalStorage / AppStorage中的属性更改,并导致绑定的状态量更改其值时:

  1. 框架观察到了变化,启动重新渲染
  2. 根据框架持有的两个map,找到被这些状态变量管理的UI组件,以及这些UI组件对应的更新函数,执行这些更新函数,实现最小化的更新

自定义组件的删除

如果if组件的分支改变,或者ForEach循环渲染中数组的个数改变,组件将被删除:

  1. 调用aboutToDisappear(ArkUI的节点删除机制是:后端节点直接从组件树上摘下,后端节点被销毁,对前端节点解引用,当前端节点已经没有引用时,将被JS虚拟机垃圾回收)
  2. 删除自定义组件和他的变量

@Builder装饰器:自定义构建函数

ArkUI还提供了更轻量化的UI元素复用机制@Builder,被@Builder修饰的函数遵循build函数语法规则,开发者可将简单的UI元素抽象成一个方法,在build中调用

@Builder修饰的函数也叫自定义构建函数

装饰器使用说明

自定义组件内自定义构建函数

定义的语法:

@Builder MyBuilderFunction({ ... })

使用方法:

this.MyBuilderFunction({ ... })
  • 允许定义多个自定义构建函数,被认为是组件私有的、特殊类型的成员函数
  • 自定义构建函数可以再所属组件的build方法和其他自定义构建中使用,但不允许在组件外使用
  • this指代的是当前所属组件,组件的状态状态变量可以在自定义构建函数中使用

全局自定义构建函数

定义的语法:

@Builder function MyGlobalBuilderFunction({ ... })

使用方法:

MyGlobalBuilderFunction()
  • 全局的自定义函数可以被整个应用获取,不允许使用this和bind方法
  • 如果不涉及的组件的变化,建议使用全局的自定义构建函数

参数传递规则

自定义构建函数的参数传递有按值传递和按引用传递两种方式,需要遵循以下规则:

  • 参数类型必须和声明的类型一致,不允许undefined、null和返回undefined和null的表达式
  • 在自定义构建函数内部,不允许改变参数值,
  • 构建函数内语法遵循UI语法规则

按引用传递参数

传递的参数可以为状态变量,且状态变量的改变会引起@Builder方法内的UI刷新,传递方式为$$

@Builder function ABuilder($$: { paramA1: string }) {
  Row() {
    Text(`UseStateVarByReference: ${$$.paramA1} `)
  }
}
@Entry
@Component
struct Parent {
  @State label: string = 'Hello';
  build() {
    Column() {
      // 在Parent组件中调用ABuilder的时候,将this.label引用传递给ABuilder
      ABuilder({ paramA1: this.label })
      Button('Click me').onClick(() => {
        // 点击“Click me”后,UI从“Hello”刷新为“ArkUI”
        this.label = 'ArkUI';
      })
    }
  }
}

按值传递参数

传递的参数发生变化时,不会引起@Builder内UI刷新

@Builder function ABuilder(paramA1: string) {
  Row() {
    Text(`UseStateVarByValue: ${paramA1} `)
  }
}
@Entry
@Component
struct Parent {
  label: string = 'Hello';
  build() {
    Column() {
      ABuilder(this.label)
    }
  }
}

简单理解:按值传递相当于一次性调用构造函数,按引用传递相当于绑定

@BuilderParam装饰器:引用@Builder函数

当开发者创建了自定义组件,并想对该组件添加特定功能时,比如添加一个点击跳转操作。如果直接在组件内嵌入方法,那么所有引用这个组件的页面就都添加了这个功能,这可能不是开发者想要的。ArkUI引入了@BuilderParam装饰器,来装饰指向@Builder方法的变量,类似于slot占位符,在指定位置加入自己想要的东西,并且不会影响其他使用这个组件的地方。

装饰器使用说明

初始化@BuilderParam装饰的方法

@BuilderParam装饰的方法只能被自定义构建函数初始化

  • 使用所属自定义组件的自定义构建函数或者全局的自定义构建函数,在本地初始化@BuilderParam

    @Builder function GlobalBuilder0() {}
    
    @Component
    struct Child {
      @Builder doNothingBuilder() {};
    
      @BuilderParam aBuilder0: () => void = this.doNothingBuilder;
      @BuilderParam aBuilder1: () => void = GlobalBuilder0;
      build(){}
    }
    
  • 用父组件自定义构建函数初始化子组件@BuilderParam装饰的方法

    @Component
    struct Child {
      @BuilderParam aBuilder0: () => void;
    
      build() {
        Column() {
          this.aBuilder0()
        }
      }
    }
    
    @Entry
    @Component
    struct Parent {
      @Builder componentBuilder() {
        Text(`Parent builder `)
      }
    
      build() {
        Column() {
          Child({ aBuilder0: this.componentBuilder })
        }
      }
    }
    

显示效果如下图:
在这里插入图片描述
这里官方文档没有说明,但是子组件定义slot的时候,给出的样例中,给slot赋值了一个默认的空构造器,猜测slot需要空构造器来占位,当父组件不指定该slot的时候,渲染过程中实际调用了空构造函数,而不是没渲染这个slot。

在开发中,需要注意this指向正确。

尾随闭包初始化组件

在自定义组件中使用@BuilderParam装饰的属性时也可通过尾随闭包进行初始化。在初始化自定义组件时,组件后紧跟一个大括号“{}”形成尾随闭包场景。(其实可以理解为定义一个匿名函数,当做参数传递给slot)

// xxx.ets
@Component
struct CustomContainer {
  @Prop header: string;
  @BuilderParam closer: () => void

  build() {
    Column() {
      Text(this.header)
        .fontSize(30)
      this.closer()
    }
  }
}

@Builder function specificParam(label1: string, label2: string) {
  Column() {
    Text(label1)
      .fontSize(30)
    Text(label2)
      .fontSize(30)
  }
}

@Entry
@Component
struct CustomContainerUser {
  @State text: string = 'header';

  build() {
    Column() {
      // 创建CustomContainer,在创建CustomContainer时,通过其后紧跟一个大括号“{}”形成尾随闭包
      // 作为传递给子组件CustomContainer @BuilderParam closer: () => void的参数
      CustomContainer({ header: this.text }) {
        Column() {
          specificParam('testA', 'testB')
        }.backgroundColor(Color.Yellow)
        .onClick(() => {
          this.text = 'changeHeader';
        })
      }
    }
  }
}

效果如下(点击黄色区域,会改变标题为‘changeHeader’):
在这里插入图片描述

@Styles装饰器:定义组件重用样式

提供了提炼公共样式进行复用的装饰器@Styles。

@Styles装饰器可以将多条样式设置提炼成一个方法,直接在组件声明的位置调用。

装饰器使用说明
  • 当前@Styles仅支持通用属性和通用事件

  • @Styles不支持参数

  • @Styles可以定义在组件内或全局,在全局定义时需在方法名前面添加function关键字,组件内定义时则不需要添加function关键字

    // 全局
    @Styles function functionName() { ... }
    
    // 在组件内
    @Component
    struct FancyUse {
      @Styles fancy() {
        .height(100)
      }
    }
    
  • 定义在组件内的@Styles可以通过this访问组件的常量和状态变量,并可以在@Styles里通过事件来改变状态变量的值

  • 组件内的@Styles的优先级高于全局@Styles

@Extend装饰器:定义扩展组件样式

在@Styles的基础上,提供了@Extend,用于扩展原生组件的样式。

装饰器使用说明
@Extend(UIComponentName) function functionName { ... }

使用规则

  • 和@Styles不同,@Extend仅支持定义在全局,不支持组件内部定义

  • 和@Styles不同,@Extend支持封装指定的组件的私有属性和私有事件和预定义相同组件的@Extend方法

    // @Extend(Text)可以支持Text的私有属性fontColor
    @Extend(Text) function fancy () {
      .fontColor(Color.Red)
    }
    // superFancyText可以调用预定义的fancy
    @Extend(Text) function superFancyText(size:number) {
        .fontSize(size)
        .fancy()
    }
    
  • 和@Styles不同,@Extend装饰的方法支持参数,开发者可以在调用时传递参数,需要遵循TS方法传值调用

  • @Extend装饰的方法的参数可以作为function,作为Event事件的句柄

    @Extend(Text) function makeMeClick(onClick: () => void) {
      .backgroundColor(Color.Blue)
      .onClick(onClick)
    }
    
    @Entry
    @Component
    struct FancyUse {
      @State label: string = 'Hello World';
    
      onClickHandler() {
        this.label = 'Hello ArkUI';
      }
    
      build() {
        Row({ space: 10 }) {
          Text(`${this.label}`)
            .makeMeClick(this.onClickHandler.bind(this))
        }
      }
    }
    
  • @Extend的参数可以作为状态变量,当状态变量改变时,UI可以正常的被刷新渲染

stateStyles:多态样式

@Styles和@Extend仅仅应用于静态页面的样式复用,是stateStyles可以依据组件的内部状态的不同,快速的设置不同样式。

概述

stateStyles是属性方法,可以根据UI内部状态来设置样式,类似于css伪类,但语法不同。ArkUI提供四种状态:

  • focused:获焦态
  • normal:正常态
  • pressed:按压态
  • disabled:不可用态
@Styles和stateStyles联合使用
@Entry
@Component
struct MyComponent {
  @Styles normalStyle() {
    .backgroundColor(Color.Gray)
  }

  @Styles pressedStyle() {
    .backgroundColor(Color.Red)
  }

  build() {
    Column() {
      Text('Text1')
        .fontSize(50)
        .fontColor(Color.White)
        .stateStyles({
          normal: this.normalStyle,
          pressed: this.pressedStyle,
        })
    }
  }
}
在stateStyles里可以使用常规变量和状态变量
@Entry
@Component
struct CompWithInlineStateStyles {
  @State focusedColor: Color = Color.Red;
  normalColor: Color = Color.Green

  build() {
    Column() {
      Button('clickMe').height(100).width(100)
        .stateStyles({
          normal: {
            .backgroundColor(this.normalColor)
          },
          focused: {
            .backgroundColor(this.focusedColor)
          }
        })
        .onClick(() => {
          this.focusedColor = Color.Pink
        })
        .margin('30%')
    }
  }
}

状态管理

渲染控制

资源访问

开发基础知识

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值