鸿蒙HarmonyOS4.0 -(ArkTs)

基本语法

  • 装饰器:如下图@Entry、@Component、@State都是装饰器。
    • @Component表示自定义组件。
    • @Entry表示该自定义组件的入口组件。
    • @State表示组件中的状态变量,状态变量的变化会触发UI的刷新。
  • UI描述:以声明式的方式来描述UI的结构,如上图build()方法中的代码。
  • 自定义组件:可复用的UI组件,如上图被@Component装饰的struct App。
  • 属性方法:通过链式调用使用更多属性,如上图.width('100%').height('100%')等。
  • 事件方法:通过链式调用使用更多事件逻辑,如上图中的.onClick(()=>{ })等。

鸿蒙HarmonyOS4.0 -(ArkTs)_第1张图片

@Entry
@Component
struct App {
  @State myText: string = 'HarmonyOS4.0';

  build() {
    Column() {
      Text(`${this.myText}`).fontSize(32).fontWeight(800)
      Button('点击').onClick(() => {
        this.myText = '欢迎使用鸿蒙'
      }).width(100).margin({top:20})
    }.width('100%').height('100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

  }
}

创建自定义组件

注意:@Entry装饰的组件,其build函数下的根结点必须为容器组件,并且forEach不能作为根节点。     

           @Component装饰的组件,其build函数下的根结点可以为非容器组件,并且forEach不能作为根节点。            

1、在入口组件内部使用自定义组建
@Component
struct ExanpleComponent {
  @State textValue: string = '组件状态'

  build() {
    Text(this.textValue)
      .fontSize(32)
      .fontWeight(600)
      .fontColor('#e33')
      .onClick(() => {
        this.textValue = '组件状态变化'
      })
  }
}

@Entry
@Component
struct App {
  @State myText: string = 'HarmonyOS4.0';

  build() {
    Column() {
      ExanpleComponent()
      Text(`${this.myText}`)
        .fontSize(32)
        .fontWeight(800)
      Button('点击')
        .width(100)
        .margin({ top: 20 })
        .onClick(() => {
          this.myText = '欢迎使用鸿蒙'
        })
    }.width('100%').height('100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

  }
}
2、从外部导入使用自定义组建

Index.ets @Entry入口文件

鸿蒙HarmonyOS4.0 -(ArkTs)_第2张图片

Example.ets @Component自定义组件文件

鸿蒙HarmonyOS4.0 -(ArkTs)_第3张图片

生命周期(页面和自定义组件)

1、页面生命周期,即被@Entry修饰的组件生命周期
  • onPageShow:页面每次显示时触发。
  • onPageHide:页面每次隐藏时触发。
  • onBackPress:当用户点击返回按钮时出发。
2、组件生命周期,即被@Component修饰的组件生命周期
  • aboutToAppear:组件刚出现的时候回调该接口,具体为在创建自定义组件实例后早build函数前。
  • aboutToDisappear:在自定义组件销毁时执行。

鸿蒙HarmonyOS4.0 -(ArkTs)_第4张图片

@Styles

注意:@Style不能有参数。

// 定义全局@style样式
@Styles function publicStyle() {
  .width('100%')
  .height('100%')
  .backgroundColor('#3ce')
}

@Entry
@Component
struct App {
  @State myText: string = 'HarmonyOS4.0';
  // 定义局部@style样式
  @Styles internalStyle(){
    .width(200)
    .margin({ top: 20 })
  }

  build() {
    Column() {
      Button(this.myText)
        .internalStyle()
        .fontSize(20)
        .onClick(() => {
          this.myText = '欢迎使用鸿蒙'
        })
    }.publicStyle().justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)

  }
}

@Extend

概念

  • 和@Style不同,@Extend仅支持定义在全局,不支持在组件内部定义。
  • 和@Style不同,@Extend装饰的方法支持参数,可以在调用时传递参数
// 定义全局@Extend样式
@Extend(Column) function publicStyle(width:string,height:string) {
  .width(width)
  .height(height)
  .backgroundColor('#3ae')
}

@Entry
@Component
struct App {
  @State myText: string = 'HarmonyOS4.0';

  build() {
    Column() {
      Button(this.myText)
        .fontSize(20)
        .onClick(() => {
          this.myText = '欢迎使用鸿蒙'
        })
    }.publicStyle('100%','100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)
  }
}

stateStyles多态样式

概述

stateStyles是属性方法,类似于css伪类,ArkUI提供了以下四种状态:

  • focused:获焦状态
  • normal:正常状态
  • pressed:按压状态
  • disabled:不可用状态
@Styles function focusedStyle() {
  .backgroundColor('red')
}

@Entry
@Component
struct App {
  @State myText: string = 'HarmonyOS4.0';
  @Styles  pressedStyle() {
  .backgroundColor('green')
}
  build() {
    Column() {
      Button(this.myText)
        .fontSize(20)
        .stateStyles({
          focused: focusedStyle,
          pressed: this.pressedStyle,
          normal: {
            .backgroundColor('blue')
          },
        })
        .onClick(() => {
          this.myText = '欢迎使用鸿蒙'
        })
    }.width('100%').height('100%').justifyContent(FlexAlign.Center).alignItems(HorizontalAlign.Center)
  }
}

@State状态管理

概念

  • 状态变量:被@State装饰的变量,状态变量的状态值的改变会引起UI的渲染更新。
  • 常规变量:没有被@State装饰的变量,它的改变永远不会引起UI的渲染更新。
@Component
struct MyComponent {
  @State count: number = 0;
  private increaseBy: number = 1;

  build() {
  }
}

@Component
struct Parent {
  build() {
    Column() {
      // 从父组件初始化,覆盖本地定义的默认值
      MyComponent({ count: 1, increaseBy: 2 })
    }
  }
}

@Prop父子单项同步(父传子)

概述

  • 单项同步:对父组件的状态变量值的修改,将同步到子元素@Prop装饰的变量,子组件@Prop变量的修改不会同步到父组件的状态变量上。

注意:@props装饰器不能在@Entry装饰的自定义组件中使用。

@Component
struct Child {
  @Prop count: number;

  build() {
    Column() {
      Text(`子组件: ${this.count} `)
      // @Prop装饰的变量不会同步给父组件
      Button(`子组件-1`).onClick(() => {
        this.count -= 1;
      }).margin({ top: 24 })
    }
  }
}

@Entry
@Component
struct Parent {
  @State num: number = 0;

  build() {
    Column() {
      Text(`父组件:${this.num}`)
      // 父组件的修改会同步给子组件
      Button(`父组件+1`).onClick(() => {
        this.num += 1;
      }).margin({ top: 24 })
      // 子组件
      Child({ count: this.num }).margin({ top: 24 })
    }.width('100%').justifyContent(FlexAlign.Center).margin({ top: 24 })

  }
}

@Link父子双向同步(父传子、子传父)

概述

  • 双向同步:对父组件的状态变量值的修改,将同步到子元素@Link装饰的变量,子组件@Link变量也将同步到父组件的状态变量上。

注意:@Link装饰器不能在@Entry装饰的自定义组件中使用。

@Component
struct Child {
  @Link items: number[];

  build() {
    Column() {
      Button(`子元素修改数组`).onClick(() => {
        this.items = [100, 200, 300];
      })
      ForEach(this.items, item => {
        Text(`${item}`)
      })
    }
  }
}

@Entry
@Component
struct Parent {
  @State arr: number[] = [1, 2, 3];

  build() {
    Column() {
      Button(`父元素修改数组`).onClick(() => {
        this.arr = [5, 6, 7];
      })
      ForEach(this.arr,
        item => {
          Text(`${item}`)
        }
      )
      Child({ items: $arr })


    }
  }
}

@Provide和@Consume后代组件双向同步(跨组建传参)

概述

  • 双向同步:@Provide与@Consume,应用于后代组件的数据双向同步,应用于数据在多个层级之间传递,实现跨层级传递。
  • 介绍:@Provide装饰的变量是在祖先节点中,是变量的提供者,@Consume装饰的变量是在后代组件中,是变量的消费者。

注意:@Provide与@Consume装饰的变量必须通过相同的属性名进行同步数据。

@Component
struct CompD {
  // @Consume装饰的变量通过相同的属性名绑定其祖先组件CompA内的@Provide装饰的变量
  @Consume publicValue: number;
  build() {
    Column() {
      Text(`D组件${this.publicValue}`)
      Button(`D组件按钮-1`)
        .onClick(() => this.publicValue -= 1)
    }
    .width('50%')
  }
}

@Component
struct CompC {
  build() {
    CompD()
  }
}

@Component
struct CompB {
  build() {
    CompC()
  }
}

@Entry
@Component
struct CompA {
  // @Provide装饰的变量publicValue由入口组件CompA提供其后代组件
  @Provide publicValue: number = 0;

  build() {
    Column() {
      Text(`A组件${this.publicValue}`)
      Button(`A组件按钮+1`)
        .onClick(() => this.publicValue += 1)
      CompB()
    }
  }
}

@Observed和@ObjectLink多层嵌套双向同步

概述

  • 上文所述的装饰器只能观察到一层的变化,对于多层嵌套的情况,比如二维数组、多维对象,它们其他层级的变化是无法被观察的,因此引出了@Observed和@ObjectLink装饰器。

注意:

  • @ObjectLink装饰器不能在@Entry装饰的自定义组件中使用。
  • @ObjectLink装饰的变量不能被赋值。
// 开发进行中...

@Watch监听状态的变化

概述

  • LocalStorage是页面级的UI存储,通过@Entry装饰器接收的参数可以在页面内共享一个LocalStorage实例。
@Entry
@Component
struct CompA {
  @Watch('change') @State count: number = 1

  change() {
    console.log(`状态变化${this.count}`)
  }

  build() {
    Column() {
      Button(`点击状态变化${this.count}`)
        .onClick(() => {
          this.count++
        })
    }
  }
}

LocalStorage页面级UI状态存储

概述

  • LocalStorage是页面级的UI存储,通过@Entry装饰器接收的参数可以在页面内共享一个LocalStorage实例。
  • 被@Entry装饰的@Component,可以被分配一个LocalStorage实例,此组件的所有子组件都将获取对该LocalStorage实例的访问权限,一个LocalStorage实例在组建数上可以分配给多个组件。
  • 被@Component装饰的组件最多可访问一个LocalStorage实例和AppStorage。
  • LocalStorage根据与@Component装饰的组件的同步类型不同,提供了两个装饰器:
    •  @LocalStorageProp:@LocalStorageProp装饰的变量与LocalStorage中给予属性建立的是单向同步关系。
    •  @LocalStorageLink:@LocalStorageLink装饰的变量与LocalStorage中给予属性建立的是双向向同步关系。

注意:LocalStorage创建后,命名属性的类型不可更改

1、@LocalStorageProp —— 单项数据同步

// import { Child } from '../components/Example'

let storage = new LocalStorage({ 'PropA': 47 });

@Component
struct Child {
  @LocalStorageProp('PropA') num2: number = 1;

  build() {
    // 点击后,只改变当前组件显示的num2,不会同步到LocalStorage中
    Button(`子组件${this.num2}`)
      .onClick(() => {
        this.num2 += 1;
      })
  }
}

@Entry(storage)
@Component
struct CompA {
  @LocalStorageProp('PropA') num1: number = 1;

  build() {
    Column({ space: 15 }) {
      Child()
      // 点击后,只改变当前组件显示的num1,不会同步到LocalStorage中
      Button(`父组件 ${this.num1}`)
        .onClick(() => this.num1 += 1)
    }
  }
}

2、@LocalStorageLink  —— 双项数据同步

// import { Child } from '../components/Example'

let storage = new LocalStorage({ 'PropA': 47 });

@Component
struct Child {
  @LocalStorageLink('PropA') num2: number = 1;

  build() {
    Button(`子组件${this.num2}`)
      .onClick(() => {
        this.num2 += 1;
      })
  }
}

@Entry(storage)
@Component
struct CompA {
  @LocalStorageLink('PropA') num1: number = 1;

  build() {
    Column({ space: 15 }) {
      Child()
      Button(`父组件 ${this.num1}`)
        .onClick(() => this.num1 += 1)
    }
  }
}

AppStorage全局UI状态存储

概述

  • AppStorage是应用全局的状态存储,和LocalStorage不同的是LocalStorage是页面级的,用于页面内的数据共享,而AppStorage是应用于全局状态的共享。
  • AppStorage中也提供了两种同步类型:
    • @StorageProp:@StorageProp(key)是和AppStorage中key对应的属性建立单向数据同步。
    • @StorageLink:@StorageLink(key)是和AppStorage中key对应的属性建立双向数据同步。

1、@StorageProp —— 单项数据同步

AppStorage.SetOrCreate('PropA', 47);

@Component
struct Child {
  @StorageProp('PropA') num2: number = 1;

  build() {
    Button(`子组件${this.num2}`)
      .onClick(() => {
        this.num2 += 1;
      })
  }
}


@Entry()
@Component
struct CompA {
  @StorageProp('PropA') num1: number = 1;

  build() {
    Column({ space: 20 }) {
      Child()
      Button(`AppStorage ${this.num1}`)
        .onClick(() => this.num1 += 1)

    }
  }
}

2、@StorageLink  —— 双项数据同步

AppStorage.SetOrCreate('PropA', 47);

@Entry()
@Component
struct CompA {
  @StorageLink('PropA') storLink: number = 1;

  build() {
    Column({ space: 20 }) {
      Button(`AppStorage ${this.storLink}`)
        .onClick(() => this.storLink += 1)

    }
  }
}

总结:LocalStorage和AppStorage都是运行时内存的状态存储。

PersistentStorage持久化UI状态存储

概述

  • LocalStorage和AppStorage都是运行时的内存,在应用退出再次启动后,依然能保存选定的结果,这就需要用到PersistentStorage。
  • PersistentStorage将选定的AppStorage属性保留在设备磁盘上。
PersistentStorage.PersistProp('aProp', 47);

@Entry
@Component
struct Index {
  @StorageLink('aProp') num: number = 48

  build() {
    Row() {
      Column() {
        // 应用退出时会保存当前结果。重新启动后,会显示上一次的保存结果
        Button(`${this.num}`)
          .onClick(() => {
            this.num += 1;
          })
      }
    }
  }
}

if/else

概述

  • 条件渲染使用if/else渲染对应状态下的ui内容。
  • 鸿蒙开发推荐使用if/else,不推荐使用switch。

ForEach

概述

  • 循环渲染,需要与容器组件配合使用。
@Entry
@Component
struct Parent {
  @State simpleList: Array = ['one', 'two', 'three'];

  build() {
    Row() {
      Column() {
        ForEach(this.simpleList,     // 数据源
          (item: string) => {
            Text(item).fontSize(32)  // 组件生成函数
          },
          (item: string) => item     // 键值生成函数:为数据源arr的每个数组项生成唯一且持久的键值。
        )
      }
    }
  }
}

LazyForEach

概述

  • LazyForEach从提供的数据源中按需迭代数据,并在每次迭代过程中创建相应的组件。当在滚动容器中使用了LazyForEach,框架会根据滚动容器可视区域按需创建组件,当组件滑出可视区域外时,框架会进行组件销毁回收以降低内存占用。
  • LazyForEach必须在容器组件内使用,目前仅有List、Grid以及Swiper组件支持数据懒加载,其他组件仍然是一次性加载所有的数据。
  • LazyForEach在每次迭代中,必须创建且只允许创建一个子组件。
class BasicDataSource implements IDataSource {
  private listeners: DataChangeListener[] = []

  public totalCount(): number {
    return 0
  }

  public getData(index: number): any {
    return undefined
  }

  registerDataChangeListener(listener: DataChangeListener): void {
    if (this.listeners.indexOf(listener) < 0) {
      console.info('add listener')
      this.listeners.push(listener)
    }
  }

  unregisterDataChangeListener(listener: DataChangeListener): void {
    const pos = this.listeners.indexOf(listener);
    if (pos >= 0) {
      console.info('remove listener')
      this.listeners.splice(pos, 1)
    }
  }

  notifyDataReload(): void {
    this.listeners.forEach(listener => {
      listener.onDataReloaded()
    })
  }

  notifyDataAdd(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataAdd(index)
    })
  }

  notifyDataChange(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataChange(index)
    })
  }

  notifyDataDelete(index: number): void {
    this.listeners.forEach(listener => {
      listener.onDataDelete(index)
    })
  }

  notifyDataMove(from: number, to: number): void {
    this.listeners.forEach(listener => {
      listener.onDataMove(from, to)
    })
  }
}

class MyDataSource extends BasicDataSource {
  // 初始化数据列表
  private dataArray: string[] = ['demo1', 'demo2', 'demo3', 'demo4']

  public totalCount(): number {
    return this.dataArray.length
  }

  public getData(index: number): any {
    return this.dataArray[index]
  }

  public addData(index: number, data: string): void {
    this.dataArray.splice(index, 0, data)
    this.notifyDataAdd(index)
  }

  public pushData(data: string): void {
    this.dataArray.push(data)
    this.notifyDataAdd(this.dataArray.length - 1)
  }
}

@Entry
@Component
struct MyComponent {
  private data: MyDataSource = new MyDataSource()

  build() {
    List({ space: 3 }) {
      LazyForEach(this.data, (item: string) => {
        ListItem() {
          Row() {
            Text(item).fontSize(20).margin({ left: 10 })
          }.margin({ left: 10, right: 10 })
        }
        .onClick(() => {
          // 每点击一次列表项,数据增加一项
          this.data.pushData(`demoVale:${this.data.totalCount()}`)

        })
      }, item => item)
    }.backgroundColor('red')
  }
}

应用/组件配置

概述

  • 应用图标、应用标签和入口图标、入口标签的配置,分别对应app.json5配置文件和module.json5配置文件文件中的icon和label标签。
  • 应用图标和标签是在设置应用中使用,例如设置应用中的应用列表。
  • 入口图标是应用安装完成后在设备桌面上中使用。

鸿蒙HarmonyOS4.0 -(ArkTs)_第5张图片

1、应用配置

鸿蒙HarmonyOS4.0 -(ArkTs)_第6张图片

2、入口配置

鸿蒙HarmonyOS4.0 -(ArkTs)_第7张图片

你可能感兴趣的:(harmonyos,鸿蒙,鸿蒙系统)