ArkTsUI入门

ArkUI

构建页面思路:排版 -> 内容 -> 美化

一般先设置Column为列,Row为行。这两个均为容器组件。

build的最外层只能有一个容器组件,也就是root节点(只能有一个根节点)

设置居左:Column和Row都设置width('100%')

struct Index {
  @State message: string = 'Hello World';
  build() {
    Column(){ //build的最外层只能有一个容器组件,也就是root节点;容器组件
      //Text为基础组件
      Text("小说简介").width('100%').fontSize(20).
        fontWeight(FontWeight.Bold).backgroundColor(Color.Grey).
        height(40)
      Row(){
        Text("都市")
          .width(50)
          .height(30)
          .backgroundColor(Color.Orange)
        Text("生活")
          .width(50)
          .height(30)
          .backgroundColor(Color.Pink)
        Text("情感")
          .width(50)
          .height(30)
          .backgroundColor(Color.Yellow)
        Text("男频")
          .width(50)
          .height(30)
          .backgroundColor(Color.Red)
      }.width('100%')
    }.width('100%')
  }
}

显示页面

文字色值写法:2种

文字溢出省略、行高

注意:textOverflow需要传一个对象进去,可以使用lineHeight设置行高。

Text('12345678901234567890123456789012345678901234567890' +
        '12345678901234567890123456789012345678901234567890')
        .textOverflow({overflow:TextOverflow.Ellipsis}).maxLines(2)
        .lineHeight(30)

图片组件

给图片设置一致的宽高比:.aspectRatio(2.4)     宽 / 高

输入框与按钮

调整组件之间的间隙:Column({space:10})

Column({space:10}){
    TextInput({
        placeholder:'用户名'
    })

    TextInput({
        placeholder:'密码'
    }).type(InputType.Password)
    Button('登录').width(200)
}

显示展示: 

登录案例

使用column.width('100%')使图片居中;

使用column.padding(20)调整内边距;

使用Column({space : 20}) 和 Row({space : 20})调整元素之间距离。

  build() {
    Column({space:20}){
      Image($r('app.media.app_icon')).width(80)
      TextInput({placeholder : "请输入用户名"})
      TextInput({placeholder : "请输入密码"}).type(InputType.Password)
      Button("登录").width('100%')
      Row({space:15}){
        Text("前往注册")
        Text("忘记密码")
      }
    }.width('100%').padding(20)

svg图标

任易放大缩小不失真,可以改颜色。

可以使用官方的图标库进行下载:鸿蒙图标库

HarmonyOS 主题图标库 | icon素材免费下载 | 华为开发者联盟

布局元素(盒子模型)

margin - border - padding

传参数{space : 1}也可是设置外边距,但是只能设置统一值,margin可以单独设置;

如果值统一,可以直接设置数值,如果不统一,可以传对象;

border样式有三种:实线、虚线、点线。

  build() {
    Column(){
      Text('刘备').backgroundColor(Color.Gray).padding(20).margin(20).border({
        width : 3,
        color : Color.Blue,
        style : BorderStyle.Dotted
      })
      Text('关羽').backgroundColor(Color.Orange).padding(20).margin(20).border({
        width : {left:1, top:2, right:3, bottom:4},
        color : { left:Color.Blue, top:Color.Brown, right:Color.Green, bottom:Color.Red },
        style : BorderStyle.Solid
      })
      Text('张飞').backgroundColor(Color.Pink).padding({
        left : 20,
        top : 20,
        right : 20,
        bottom : 20
      }).margin(20)
    }
  }

设置圆角

Text('刘备').backgroundColor(Color.Gray).padding(20).margin(20).border({
  width : 3,
  color : Color.Blue,
  style : BorderStyle.Dotted
}).borderRadius(30).borderRadius({topLeft:10, topRight:20, bottomLeft:30, bottomRight:40})

正圆:width、height均为100,圆角设置为50。

胶囊按钮:width为100,height为50,圆角设置为25。

背景属性

图片:

.backgroundImage($r('app.media.startIcon'))//可以使用一个参数

.backgroundImage($r('app.media.startIcon'), ImageRepeat.XY)  //两个参数可以设置平铺

位置:

其中的100是虚拟像素,vp。对于不同设备会自动转换,保证不同设备视觉效果一致(推荐)。

可以使用vp2ps()转换,但是现在可能已经直接使用了,不需要转换。

大小(缩放):

组件排布(对齐)——线性布局

justifyContent(FlexAlign.Center);

个人中心元素对齐案例:

交叉轴

 对齐方式:

案例:既用到主轴对齐,有用到交叉轴对齐。

自适应伸缩.layoutWeight

按照份数权重,分配剩余空间。

layoutWeight(1),1表示在剩余的空间里占一份,不需要自适应的设置一个固定值即可。

  build() {
    Column(){
      Row(){
        Text("1").height(100).backgroundColor(Color.Brown).layoutWeight(1)
        Text("2").width(100).height(100).backgroundColor(Color.Gray).layoutWeight(1)
        Text("3").width(100).height(100).backgroundColor(Color.Pink)
      }
    }
  }

弹性布局

上图中123和线性布局基本一样,重点在4.布局换行中使用弹性布局。

单行或者单列的情况,还是优先使用线性布局(线性布局底层就是根据Flex去设计的。),而且还做了性能优化。

Flex布局:伸缩布局。当子盒子的总和溢出父盒子,默认进行压缩显示。

适用的情况:如上图阶段选择案例,多行且不规则排列的场景。

Flex是伸缩布局:

设置wrap后:

绝对定位和层级.position

默认后面的元素层级高于前面的元素,可以使用zIndex调整层级,使用zIndex时其他元素默认为0级。

层叠布局

小技巧:使用Ctrl+p在参数传对象时,可以直接看到对象的参数类型。

在使用绝对定位比较麻烦的时候,可以使用层叠布局,使得代码更简洁。

弹簧组件Blank

Blank()在两个组件之间添加,撑开中间的空间。

 Badge角标组件

用Badge包裹在需要角标的组件外。

Badge组件只能将角标放在右上、中左、中右三个位置,其他位置需要角标可以使用绝对定位来做。

网格布局Grid

GridItem中只能有且只有一个子元素,即代码中的Column;

1fr调整分几份;

Gap调整中间的间隙。

图中的左边缝隙最大,是视觉效果,图片放大后并无差异。

蒙层设置

使用层叠布局Stack,点击立即抽卡,提高蒙层的zIndex。设置透明度和动画缩放。

抽卡完整功能代码

注意随机抽卡中,修改对象数组中对象的某个值,需要修改整个对象,即arr[index] = {},重新传入一个对象,这是因为监听一个变量消耗的性能很高,对象中的数据很多的话会浪费性能。

在验证是否集齐6张卡片的时候,可以使用假设成立法,for之前定义一个flag,for中count均>0那么修改flag,最后给外部的isget(获得大奖)变量赋值。

// 定义接口 (每个列表项的数据结构)
interface ImageCount {
  url: string
  count: number
}

// 0 1 2 3 4 5
// [0,1) * 6  =>  [0,6)
// 求随机数: Math.random
// 向下取整: Math.floor
// console.log('随机数', Math.floor(Math.random() * 6))

@Entry
@Component
struct Index {
  // 随机的生肖卡序号 0-5
  @State randomIndex: number = -1 // 表示还没开始抽

  // 基于接口, 准备数据
  @State images: ImageCount[] = [
    { url: 'app.media.bg_00', count: 0 },
    { url: 'app.media.bg_01', count: 0 },
    { url: 'app.media.bg_02', count: 0 },
    { url: 'app.media.bg_03', count: 0 },
    { url: 'app.media.bg_04', count: 0 },
    { url: 'app.media.bg_05', count: 0 }
  ]

  // 控制遮罩的显隐
  @State maskOpacity: number = 0 // 透明度
  @State maskZIndex: number = -1 // 显示层级

  // 控制图片的缩放
  @State maskImgX: number = 0 // 水平缩放比
  @State maskImgY: number = 0 // 垂直缩放比

  // 控制中大奖遮罩的显隐
  @State isGet: boolean = false

  @State arr: string[] = ['pg', 'hw', 'xm'] // 奖池
  @State prize: string = '' // 默认没中奖

  build() {
    Stack() {
      // 初始化的布局结构
      Column() {
        Grid() {
          ForEach(this.images, (item: ImageCount, index: number) => {
            GridItem() {
              Badge({
                count: item.count,
                position: BadgePosition.RightTop,
                style: {
                  fontSize: 14,
                  badgeSize: 20,
                  badgeColor: '#fa2a2d'
                }
              }) {
                Image($r(item.url))
                  .width(80)
              }
            }
          })
        }
        .columnsTemplate('1fr 1fr 1fr')
        .rowsTemplate('1fr 1fr')
        .width('100%')
        .height(300)
        .margin({ top: 100 })

        Button('立即抽卡')
          .width(200)
          .backgroundColor('#ed5b8c')
          .margin({ top: 50 })
          .onClick(() => {
            // 点击时, 修改遮罩参数, 让遮罩显示
            this.maskOpacity = 1
            this.maskZIndex = 99
            // 点击时, 图片需要缩放
            this.maskImgX = 1
            this.maskImgY = 1

            // 计算随机数 Math.random()  [0,1) * (n + 1)
            this.randomIndex = Math.floor(Math.random() * 6)
          })
      }
      .width('100%')
      .height('100%')

      // 抽卡遮罩层 (弹层)
      Column({ space: 30 }) {
        Text('获得生肖卡')
          .fontColor('#f5ebcf')
          .fontSize(25)
          .fontWeight(FontWeight.Bold)
        Image($r(`app.media.img_0${this.randomIndex}`))
          .width(200)
            // 控制元素的缩放
          .scale({
            x: this.maskImgX,
            y: this.maskImgY
          })
          .animation({
            duration: 500
          })
        Button('开心收下')
          .width(200)
          .height(50)
          .backgroundColor(Color.Transparent)
          .border({ width: 2, color: '#fff9e0' })
          .onClick(() => {
            // 控制弹层显隐
            this.maskOpacity = 0
            this.maskZIndex = -1

            // 图像重置缩放比为 0
            this.maskImgX = 0
            this.maskImgY = 0

            // 开心收下, 对象数组的情况需要更新, 需要修改替换整个对象
            // this.images[this.randomIndex].count++
            this.images[this.randomIndex] = {
              url: `app.media.img_0${this.randomIndex}`,
              count: this.images[this.randomIndex].count + 1
            }

            // 每次收完卡片, 需要进行简单的检索, 判断是否集齐
            // 需求: 判断数组项的count, 是否都大于0, 只要有一个等于0,就意味着没集齐
            let flag: boolean = true // 假设集齐

            // 验证是否集齐
            for (let item of this.images) {
              if (item.count == 0) {
                flag = false // 没集齐
                break // 后面的没必要判断了
              }
            }

            this.isGet = flag

            // 判断是否中奖了, 如果是 需要抽奖
            if (flag) {
              let randomIndex: number = Math.floor(Math.random() * 3)
              this.prize = this.arr[randomIndex]
            }
          })
      }
      .justifyContent(FlexAlign.Center)
      .width('100%')
      .height('100%')
      // 颜色十六进制色值,如果是八位,前两位,就是透明度
      .backgroundColor('#cc000000')
      // 设置透明度
      .opacity(this.maskOpacity)
      .zIndex(this.maskZIndex)
      // 动画 animation, 当我们元素有状态的改变,可以添加animation做动画
      .animation({
        duration: 200
      })

      // 抽大奖的遮罩层
      if (this.isGet) {
        Column({ space: 30 }) {
          Text('恭喜获得手机一部')
            .fontColor('#f5ebcf')
            .fontSize(25)
            .fontWeight(700)
          Image($r(`app.media.${this.prize}`))
            .width(300)
          Button('再来一次')
            .width(200)
            .height(50)
            .backgroundColor(Color.Transparent)
            .border({ width: 2, color: '#fff9e0' })
            .onClick(() => {
              this.isGet = false
              this.prize = ''
              this.images = [
                { url: 'app.media.bg_00', count: 0 },
                { url: 'app.media.bg_01', count: 0 },
                { url: 'app.media.bg_02', count: 0 },
                { url: 'app.media.bg_03', count: 0 },
                { url: 'app.media.bg_04', count: 0 },
                { url: 'app.media.bg_05', count: 0 }
              ]
            })
        }
        .justifyContent(FlexAlign.Center)
        .width('100%')
        .height('100%')
        .backgroundColor('#cc000000')
      }
    }

  }
}

Swiper轮播组件——轮播图

一、基础用法

切记不要在内层设置尺寸,要在Swiper设置。

二、常用属性

三、自定义属性

自定义圆点,indicator传true/false为打开关闭圆点,前三个设置默认状态下圆点,后三个设置选中状态下圆点。

样式和结构的重用

@Extend:针对组件(样式、事件)进行扩展实现复用效果。

可以传参,只能全局定义。

@Styles: 抽取通用属性、事件 实现复用效果。

不可以传参,可以在struct内编写,此时不用加function

@Builder:自定义构建函数(针对结构、样式、事件进行扩展实现复用)。

可以传参、需要访问内部状态可以在局部定义、可以写结构。

也可以自定义组件来实现,比较简单的可以使用@Builder

可以全局定义,也可以在组件内定义。 如果需要访问内部效果,必须在组件内定义,这样才能通过this访问到自己的状态。

不同的是,不用点,直接写函数,如下图navItem。可以理解为一个轻量的组件封装。 

Scroll

一、核心用法

Scroll内部只支持一个子组件。

二、常见属性

Scroll(){}
.scrollable(ScrollDirection.Vertical) //纵向滑动
.scrollBar(BarState.Auto) //on一直显示 off隐藏 auto滑动时显示
.scrollBarColor(Color.Orange) //颜色
.scrollBarWidth(20) //宽度
.edgeEffect(EdgeEffect.Spring) //效果

三、控制器(返回页面顶部、获取滚动距离)

返回页面顶部;获取滚动距离。

三步走:

1、创建scroller对象;

2、将对象和Scroll绑定;

3、this.scroller.scrollEdge(Edge.Top)。 //也可以用start,效果一样

四、事件

案例:超过400显示,反之隐藏。设置一个@state变量存储Y的偏移量,在onscroll中赋值。

if (偏移量 > 400) {

        小火箭组件
}

因为添加@state后这个变量就是一个实时变化的值,所以if可以直接写在这里。

Scroll(){}
.onScroll((x, y) => { //滚动时,会一直触发

});

TabBar组件

基本用法和属性

barPosition :调整位置 开头 或 结尾 (参数)

vertical :调整导航 是否垂直

scrollable :是否 手势滑动 切换

animationDuration :点击滑动动画时间

@Entry
@Component
struct Index {
  build() {
    Tabs({barPosition:BarPosition.End}){
      TabContent(){
        Text("首页内容")
      }.tabBar("首页")
      TabContent(){
        Text("推荐内容")
      }.tabBar("推荐")
      TabContent(){
        Text("发现内容")
      }.tabBar("发现")
      TabContent(){
        Text("我的内容")
      }.tabBar("我的")
    }.vertical(false).scrollable(true).animationDuration(0)
  }
}

滚动导航栏

如果导航栏的内容较多,屏幕无法容纳时,可以将他设置为滚动

.barMode(BarMode.Scrollable) //BarMode.Fixed 默认值 固定

自定义TabBar(加图片等)

这样可以在自定义的函数中加入图片、结构(column)等。

可以传参数。

高亮切换

监听事件有两个:

点击和滑动都触发:onChange(event: (index: number) => void)

只有点击都触发:onTabBarClick(event: (index: number) => void)

1、通过Tabs(){}.onChange获取index,赋值给外部的selectIndex

2、给自定义TabBar增加参数:index,高亮的图片

3、在自定义TabBar中增加比较语句,与selectIndex相等的话就文字变色,切换高亮图片。

小米有品案例

对于这种中间有特殊结构的,再重新自动以一个TabBar放在中间即可。

自定义组件

1、基本使用

由框架直接提供的称为 系统组件,由开发者定义的称为 自定义组件。

和空项目给出的是一样的,空项目多一个@Entry,可以复制一下直接改名字即可。

使用自定义组件:HelloComponent()

// 定义
@Component
struct HelloComponent {
    // 状态变量
    @State message:string =''
    build(){
    // .... 描述 UI
    }
}

2、自定义组件可以使用通用样式、通用事件

HelloComponent().width().onClick()

在单独的文件中写事件,添加export导出,export struct HelloComponent{} 

如果想要单独预览组件,可以使用 @Preview 进行装饰

3、状态变量、成员变量(可赋值为函数),外部可传参覆盖

成员函数不可覆盖。

4、@BuilderParam传UI

3中,自定义组件传递文本参数;如果内部结构有所不同那么就不能直接复用,BuilderParam可以传递内部结构。

状态管理-@state

当运行时的 状态变量 变化,带来UI的重新渲染,在ArkUI中统称为 状态管理机制。

变量必须被 装饰器 装饰才可以成为状态变量。

@State自己的状态

注意:不是所有的状态变量改变都会引起界面的刷新的,只有被框架观察到的修改才会引起UI刷新。

1. boolean、string、number类型时,可以观察到数值的变化

2. class或者Object时,可观察 自身的赋值 的变化, 第一层属性赋值的变化,即Object.keys(observedObject.toString()) 返回的属性。

class  Car {
  name:string = ""
}
class Person{
  name:string = ""
  car:Car = {name:""}
}

@Entry
@Component
struct Index {
  @State person : Person = {
    name:'jack',
    car:{
      name:'bigCar'
    }
}
  build() {
    Column(){
      Button("button").onClick(()=>{
        this.person.car.name = "smallCar"
      })
      Text(JSON.stringify(this.person)).fontSize(20)
      Text(Object.keys(this.person).toString())
    }
  }
}

@Prop-父子单向

在使用自定义组件时,子组件想使用父组件的@state变量,只通过传值的方式,当父组件变量变化时,子组件变量值是无法改变的,也就无法重新渲染UI界面。

给子组件中的变量添加@Prop,这样在进行传值时(通过子组件参数),父组件值修改,子组件的值也会修改

如果想要在子组件中修改父组件的值,需要在子组件汇总添加一个函数并由父组件调用赋值,这样这个函数在子组件中调用时,就修改了父组件的@state,但是这样本质上还是在父组件中修改;可以选择在传值时添加一个参数,将这个参数赋值给父组件的@state变量,然后在子组件调用时传参,这样就实现了在子组件中改变父组件@state变量。

父组件中传递的函数要是用箭头函数,因为只有这样this才指向父组件,不然this就会指向子组件。

@Component
struct sonCom {
  @Prop info:string
  chanInfo = (newInfo:string)=>{ //需要通过父组件的函数来修改
  }
  build() {
    Column(){
      Text(this.info)
      Button().onClick(()=>{
        this.chanInfo("son222")
      })
    }
  }
}

@Entry
@Component
struct FatherCom {
  @State info:string = "111"
  build() {
    Column(){
      Text(this.info)
      Button().onClick(()=>{
        this.info = "father222"
      })
      sonCom({
        info:this.info,
        chanInfo:(newInfo:string)=>{ //这里需要的是一个箭头函数,不然this就是子组件的this了
          // 这里使用了一个小技巧,使得可以再子组件中赋值。
          this.info = newInfo //如果写成固定值,那么本质上还是在父组件中修改。
        }
      }).width('80%').height(200).backgroundColor(Color.Orange)
    }.width('100%').height(300).backgroundColor(Color.Pink)
  }
}

@Link双向同步

适应@Link可以实现父组件和子组件的双向同步。

父组件@State变量修改,子组件对应的被@Link修饰的变量也修改;在子组件内修改,父组件变量也会改变。

@Provide 和 @Consume

同@Link一样,数据可以双向联动,而且可以跨层级双向联动。

比如父组件使用@Provide修饰,孙组件中使用@Consume修饰,任意处更改此变量,所有组件中有这个变量的,这个变量值都会改变。

被它们修饰的变量名必须一致。

@Observed 和 @ObjectLink

装饰器仅能观察到第一层的变化。对于多层嵌套的情况,比如对象数组等。

他们的第二层的属性变化是无法观察到的。这就引出了@Observed/@ObjectLink装饰器。

作用:用于在涉及嵌套对象或数组的场景中进行双向数据同步

注意:@ObjectLink修饰符不能用在Entry修饰的组件中

@Observed只能对class进行装饰,在类定义的时候添加@Observed装饰器。此时这个类实例化出来的所有对象都会被自动添加setter和getter函数,来监视他的状态。

在非Enter修饰的组件中,使用@ObjectLink修饰的对象,可以自动更新。

属性更新的逻辑:当我们@Observed装饰过的数据,属性改变时,就会监听到;遍历依赖它的@ObjectLink包装类,通知数据更新。

如何证明能见听到呢?在带有Enter的父组件中调用函数打印没有带@ObjectLink包装类的变量,值也会改变,只是不更新UI界面。

当带有Enter的父组件中也有这个变量时,因为“@ObjectLink修饰符不能用在Entry修饰的组件中”,所以需要包一层。也就是再自定义一个组件,使用@ObjectLink修饰变量。

路由

页面路由指的是在应用程序中实现不同页面之间的跳转,以及数据传递。

1、创建页面

两种方式:

1、使用page创建页面,可以直接添加配置文件

2、使用ArkTs创建文件,需要在下方的resources文件夹profile文件中main_pages.json添加此文件,这样才能正常使用路由功能。

2、页面跳转和后退

两种方法,还有一个back手动返回。

3、页面栈

页面栈是用来存储程序运行时页面的一种 数据结构,遵循 先进后出 的原则

页面栈的最大容量为 32 个页面

案例:都使用pushUrl,跳转几个页面再使用getLength就是1+n;

如果C和D之间反复跳转,也会计算数量;

使用replaceUrl在CD之间跳转,不会增加页面栈长度。点击返回按钮时,如果上一层是B,那么直接返回B。

4、路由模式

路由提供了两种不同的跳转模式

1. Standard:无论之前是否添加过,一直添加到页面栈【默认常用】

2. Single:如果目标页面已存在,会将已有的最近同url页面移到栈顶【看情况使用】

在第二个参数设置 【路由模式】

router.pushUrl(options, mode)

router.pushUrl({
  url:"pages/default",
  params:{
    username:this.username
  }
}, router.RouterMode.Single)

5、跳转传参

index中的text : $$this.username,$$是双向绑定。在ArkUI框架中,$$this 是一种特殊的语法符号,主要用于​​按引用传递当前组件实例的上下文​​。在代码示例中,$$this.username 的作用是将当前组件(Index组件)的 @State 变量 username 以​​引用传递​​的方式绑定到 TextInput 组件上。

aboutToAppear已进入页面就会执行的函数——声明周期函数(钩子)

const params = router.getParams()获取数据,需要进行类型断言,自定义一个和index中相同的类型,然后就可以使用params.变量获取数据了。这是因为在default中不知道传递过来的数据是什么格式的。

钩子(Hook):在编程中,"钩子"(Hook)是一种​​通过拦截系统或应用程序的事件、函数调用或消息传递,从而修改或扩展其行为的技术​​。其核心价值在于允许开发者在不修改原有代码的情况下,插入自定义逻辑,实现对程序行为的监控、增强或重定向。

index页面

import { router } from '@kit.ArkUI'

@Entry
@Component
struct Index {
  @State username : string = ""
      build() {
        Column(){
          Text("Index页面").width(300).height(100).fontSize(30)
          TextInput({
            text : $$this.username,
            placeholder : '请输入用户名'
          }).height(100).fontSize(30)
          Button("跳转到默认").width(300).height(100).fontSize(30).onClick(()=>{
            router.pushUrl({
              url:"pages/default",
              params:{
                username:this.username
              }
            }, router.RouterMode.Single)
          })
      }.width('100%')
  }
}

default页面

import { router } from '@kit.ArkUI';
interface ParamsObj {
  username : string
}
@Entry
@Component
struct Default {
  @State message:string = '默认页面';
  @State username:string = "";
  aboutToAppear(): void {
    console.log(JSON.stringify(router.getParams()))
    const params  = router.getParams() as ParamsObj
    this.username = params.username
    console.log("this.username---", this.username)
  }

  build() {
    RelativeContainer() {
      Text(this.message + this.username)
        .id('DefaultHelloWorld')
        .fontSize($r('app.float.page_text_font_size'))
        .fontWeight(FontWeight.Bold)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
      Button("back").onClick(()=>{
        router.back()
      }).width(300).height(100).fontSize(30)
    }
    .height('100%')
    .width('100%')
  }
}

生命周期

组件 页面 在创建、显示、销毁的这一整个过程中,会自动执行 一系列的【生命周期钩子】

其实就是一系列的【函数】,让开发者有机会在特定的阶段运行自己的代码

区分 页面 和 组件:@Entry

aboutToAppear:创建组件实例后执行,可以修改状态变量

aboutToDisappear:组件实例销毁前执行,不允许修改状态变量

onPageShow:页面每次显示触发(路由过程、应用进入前后台)

onPageHide:页面每次隐藏触发(路由过程、应用进入前后台)

onBackPress:点击返回触发(return true 阻止返回键默认返回效果)

仅@Entry修饰的页面组件生效

下面的两个案例下载了一起,分别说明一下:

一、点击切换子组件显示控制子组件的显示。默认是显示的,所以输出顺序为:(只写了aboutToAppear和aboutToDisappear两个)

Index - aboutToAppear    SonCom - aboutToAppear

再次点击输出:SonCom - aboutToDisappear

二、点击跳转页面跳转到登录页面,登录页面里有一个登录子组件。

初始化后显示:Index - aboutToAppear

点击“跳转页面”后显示:

Login - aboutToAppear
LoginSon - aboutToAppear
Login - onPageShow

点击返回按钮后:

Login - onPageHide
Login - aboutToDisappear
LoginSon - aboutToDisappear

这里需要注意的是,跳转到Login时先创建组件实例,再创建子组件实例,再显示页面。

back时Login页面先隐藏,组件实例销毁函数被调用,此时发现还有子组件,所以先销毁子组件,所有出现了点打印Login的aboutToDisappear后打印LoginSon的aboutToDisappear的情况。

Index页面

import { router } from '@kit.ArkUI'

@Component
struct SonCom {
  aboutToAppear(): void {
    console.log("SonCom - aboutToAppear")
  }
  aboutToDisappear(): void {
    console.log("SonCom - aboutToDisappear")
  }
  build() {
    Column(){
      Text("我是子组件")
    }
    .width(200)
    .height(200)
    .border({width:3})
    .margin(20)
  }
}

@Entry
@Component
struct Index {
  @State show:boolean = true
  aboutToAppear(): void {
    console.log("Index - aboutToAppear")
  }
  aboutToDisappear(): void {
    console.log("Index - aboutToDisappear")
  }
  build() {
    Column(){
      Text("组件生命周期").fontSize(40)
      Button("切换子组件显示").onClick(()=>{
        this.show = !this.show
      })
      if (this.show){
        SonCom()
      }
      Button("跳转页面").onClick(()=>{
        router.pushUrl({
          url:"pages/Login"
        })
      })
    }
  }
}

Login页面

import { router } from '@kit.ArkUI';
@Component
struct LoginSon {
  aboutToAppear(): void {
    console.log("LoginSon - aboutToAppear")
  }
  aboutToDisappear(): void {
    console.log("LoginSon - aboutToDisappear")
  }
  onPageShow(): void {
    console.log("LoginSon - onPageShow")
  }
  onPageHide(): void {
    console.log("LoginSon - onPageHide")
  }
  build() {

  }
}
@Entry
@Component
struct Login {
  aboutToAppear(): void {
    console.log("Login - aboutToAppear")
  }
  aboutToDisappear(): void {
    console.log("Login - aboutToDisappear")
  }
  onPageShow(): void {
    console.log("Login - onPageShow")
  }
  onPageHide(): void {
    console.log("Login - onPageHide")
  }
  onBackPress(): boolean | void {
    // 自己手写返回的代码,将来定制返回的逻辑
    router.back()
  }
  build() {
    Row(){
      Text("登录").fontSize(50)
      LoginSon()
    }
  }
}

Stage模型

一、目录概览

二、app.json5 应用配置

三、UIAbility 组件

四、UIAbility 的添加 和 设置启动

五、UIAbility 组件的生命周期

六、拉起另一个UIAbility

1、相同模块

2、不同模块

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值