当前位置:   article > 正文

ArkTS基础知识【含示例源码】

arkts

ArkTS是HarmonyOS的一种应用开发语言,他在TypeScript的基础上,拓展了声明式UI、状态管理等相应的能力,让开发者以更简洁自然的方式开发高性能的应用。

千言万语不胜效果图来的直观,先看下示例的演示效果:

我们以其中一段代码来学习相关知识点:

  1. import {FontSize,FontWeight,ItemStyle,WEIGHT} from '../common/constants/Constants'
  2. @Component
  3. export struct ListItemComponent{
  4. index:number
  5. private name:Resource;
  6. @Prop vote:string;
  7. @Prop isSwitchDataSource:boolean;
  8. @State isChange:boolean=false;
  9. build(){
  10. Row(){
  11. Column(){
  12. if(this.isRenderCircleText()){
  13. this.CircleText(this.index);
  14. }else{
  15. Text(this.index.toString())
  16. .lineHeight(ItemStyle.TEXT_LAYOUT_SIZE)
  17. .textAlign(TextAlign.Center)
  18. .width(ItemStyle.TEXT_LAYOUT_SIZE)
  19. .fontWeight(FontWeight.BOLD)
  20. .fontSize(FontSize.SMALL)
  21. }
  22. }
  23. .width(ItemStyle.LAYOUT_WEIGHT_LEFT)
  24. .alignItems(HorizontalAlign.Start)
  25. Text(this.name)
  26. .width(ItemStyle.LAYOUT_WEIGHT_CENTER)
  27. .fontWeight(FontWeight.BOLDER)
  28. .fontSize(FontSize.MIDDLE)
  29. .fontColor(this.isChange?ItemStyle.COLOR_BLUE:ItemStyle.COLOR_BLACK)
  30. Text(this.vote)
  31. .width(ItemStyle.LAYOUT_WEIGHT_RIGHT)
  32. .fontWeight(FontWeight.BOLDER)
  33. .fontSize(FontSize.SMALL)
  34. .fontColor(this.isChange?ItemStyle.COLOR_BLUE:ItemStyle.COLOR_BLACK)
  35. }
  36. .height(ItemStyle.BAR_HEIGHT)
  37. .width(WEIGHT)
  38. .onClick(()=>{
  39. this.isSwitchDataSource=!this.isSwitchDataSource
  40. this.isChange=!this.isChange
  41. })
  42. }
  43. @Builder
  44. CircleText(index:number){
  45. Row(){
  46. Text(this.index.toString())
  47. .fontWeight(FontWeight.BOLD)
  48. .fontSize(FontSize.SMALL)
  49. .fontColor(Color.White);
  50. }
  51. .justifyContent(FlexAlign.Center)
  52. .borderRadius(ItemStyle.CIRCLE_TEXT_BORDER_RADIUS)
  53. .size({width:ItemStyle.CIRCLE_TEXT_SIZE,height:ItemStyle.CIRCLE_TEXT_SIZE})
  54. .backgroundColor($r('app.color.circle_text_background'))
  55. }
  56. isRenderCircleText():boolean{
  57. return this.index===1||this.index===2||this.index===3;
  58. }
  59. }

 @Component 这些带@的叫装饰器,装饰器用来装饰类、结构、方法和变量,赋予其特殊的含义和能力。

@Componet 代表的当前这个是一个自定义组件,组件名字就是ListItemComponent,他是可重用的UI单元,可以与其他组件组合

代码中的@State 也是一种装饰器,被它装饰的变量isChange的值发生变化的时候,就会触发该变量所对应的自定义组件的UI界面进行自动刷新。

build(){....} 是代表对该UI组件的描述,是基于声明式的结构,而它里边的比如 Row(),Text()这些属于内置组件,是系统提供的基础组件和容器组件,可以用来直接使用。

每个组件有自己的属性方法,使用点运算符进行链式调用;通过这些属性方法来设置对应组件的样式,绑定事件等操作。

  1. Text(this.index.toString())
  2. .lineHeight(ItemStyle.TEXT_LAYOUT_SIZE) //属性方法,设置行高
  3. .textAlign(TextAlign.Center)//属性方法,设置文字对齐方式
  4. .width(ItemStyle.TEXT_LAYOUT_SIZE)//属性方法,文本框宽度
  5. .fontWeight(FontWeight.BOLD)//属性方法,设置字体粗细
  6. .fontSize(FontSize.SMALL)//属性方法,设置字体大小

比如Row()组件下的onClick就是事件方法,可以用来实现点击每一样数据的时候来触发调用。

  1. .onClick(()=>{
  2. this.isSwitchDataSource=!this.isSwitchDataSource
  3. this.isChange=!this.isChange

在ArkTS中,除了类似,Text、Button、Image、TextInput、Column、Row、Stack、List等等大量的内置组件外,我们为了满足某些效果,结合这些内置组件组合封装后的组件就都称为自定义组件。

我们一般的开发流程是先基于内置组件组合好一些自定义组件,然后再通过组合自定义组件形成一个个完整的页面。

我们自己写的自定义组件在使用上和内置组件是一样的,直接引用就可以了,当一个组件中使用另外一个组件的内容时,这个组件就被称为父组件

  1. /*
  2. * Copyright (c) 2022 Huawei Device Co., Ltd.
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. import prompt from '@ohos.prompt';
  16. import { RankViewModel } from '../viewmodel/RankViewModel';
  17. import { RankData } from '../common/bean/RankData';
  18. import { ListHeaderComponent } from '../view/ListHeaderComponent';
  19. import { TitleComponent } from '../view/TitleComponent';
  20. import { ListItemComponent } from '../view/ListItemComponent';
  21. import { APP_EXIT_INTERVAL, Style, TAG, TIME, TITLE, WEIGHT } from '../common/constants/Constants';
  22. let rankModel: RankViewModel = new RankViewModel();
  23. @Entry
  24. @Component
  25. //相对于TitleComponent等自定义组件,Index就是父组件
  26. struct Index {
  27. @State dataSource1: RankData[] = [];
  28. @State dataSource2: RankData[] = [];
  29. // The State is used to decide whether to switch the data of RankList.
  30. @State isSwitchDataSource: boolean = true;
  31. // It will record the time of clicking back button of system navigation.
  32. private clickBackTimeRecord: number = 0;
  33. aboutToAppear() {
  34. console.log(`${TAG} aboutToAppear`);
  35. this.dataSource1 = rankModel.loadRankDataSource1();
  36. this.dataSource2 = rankModel.loadRankDataSource2();
  37. }
  38. aboutToDisappear() {
  39. console.log(`${TAG} aboutToDisappear`);
  40. }
  41. onPageShow() {
  42. console.log(`${TAG} onPageShow`);
  43. }
  44. onPageHide() {
  45. console.log(`${TAG} onPageHide`);
  46. }
  47. onBackPress() {
  48. if (this.isShowToast()) {
  49. prompt.showToast({ message: $r('app.string.prompt_text'), duration: TIME });
  50. this.clickBackTimeRecord = new Date().getTime();
  51. return true;
  52. }
  53. return false;
  54. }
  55. isShowToast(): boolean {
  56. return new Date().getTime() - this.clickBackTimeRecord > APP_EXIT_INTERVAL;
  57. }
  58. build() {
  59. Column() {
  60. //相对于Index,这个就是子组件
  61. TitleComponent({ isRefreshData: $isSwitchDataSource, title: TITLE })
  62. // The head style of List component.
  63. ListHeaderComponent({
  64. paddingValue: { left: Style.RANK_PADDING,
  65. right: Style.RANK_PADDING },
  66. widthValue: Style.CONTENT_WIDTH
  67. }).margin({ top: Style.HEADER_MARGIN_TOP,
  68. bottom: Style.HEADER_MARGIN_BOTTOM })
  69. // The style of List component.
  70. this.RankList(Style.CONTENT_WIDTH)
  71. }
  72. .backgroundColor($r('app.color.background'))
  73. .height(WEIGHT)
  74. .width(WEIGHT)
  75. }
  76. @Builder RankList(widthValue: Length) {
  77. Column() {
  78. List() {
  79. ForEach(this.isSwitchDataSource ? this.dataSource1 : this.dataSource2,
  80. (item, index) => {
  81. ListItem() {
  82. ListItemComponent({ index: index + 1, name: item.name, vote: item.vote,
  83. isSwitchDataSource: this.isSwitchDataSource
  84. })
  85. }
  86. }, (item, index) => item.id)
  87. }
  88. .width(WEIGHT)
  89. .height(Style.LIST_HEIGHT)
  90. .divider({ strokeWidth: Style.STROKE_WIDTH })
  91. }
  92. .padding({ left: Style.RANK_PADDING,
  93. right: Style.RANK_PADDING })
  94. .borderRadius(Style.BORDER_RADIUS)
  95. .width(widthValue)
  96. .alignItems(HorizontalAlign.Center)
  97. .backgroundColor(Color.White)
  98. }
  99. }

如上代码片段,Index就是TitleComponent的父组件,TitleComponent就是Index的子组件,了解父子组件的关系,对我们准确理解和掌握后面的数据绑定,影响关系很重要。

我们上面的Index.ets代码片段中,还使用了@Entry装饰器,被他装饰的自定义组件表示这个组件作为页面的默认入口,加载页面时,将首先创建并呈现@Entry装饰器修改的自定义组件。

一个页面有且仅能有个@Entry。

在代码工程中,自定义组件一般分布在不同的源码文件中,因此为了能够被别的组件引用使用,我们需要在自定义组件的关键字struct 前面使用关键字export来导出组件。在父组件使用子组件是,需要先在文件开头使用import关键字导入子组件,导入方式如下面代码片段:

  1. import { ListHeaderComponent } from '../view/ListHeaderComponent';
  2. import { TitleComponent } from '../view/TitleComponent';
  3. import { ListItemComponent } from '../view/ListItemComponent';

下面我们再了解下自定义组件的生命周期相关内容。

自定义组件生命周期函数有:自定义组件的创建=>aboutToAppear()=> aboutToDisappear(),=>自定义组件销毁,我们通过两个生命周期回调函数,用于通知开发者当前组件所处的阶段。

在aboutToAppear中,我们可以用来初始化UI需要展示的数据,或者申请定时器资源等操作,这样在后续build函数中可以使用这些数据和资源来进行UI展示:

  1. aboutToAppear() {
  2. console.log(`${TAG} aboutToAppear`);
  3. this.dataSource1 = rankModel.loadRankDataSource1();
  4. this.dataSource2 = rankModel.loadRankDataSource2();
  5. }

aboutToDisappear() 在自定义组件实例被销毁时调用,我们可以在该组件生命周期回调函数中释放不再使用的资源,避免资源泄露,比如释放在aboutToAppear()申请的定时器资源等。

  1. aboutToDisappear() {
  2. console.log(`${TAG} aboutToDisappear`);
  3. }

我们需要注意和了解的是,这些生命周期回调函数都是私有的,是无法手动调用的,由系统在特定时刻自动调用执行。

对应页面的入口组件,也就是被@Entry装饰器修饰的自定义组件,系统还提供了另外的三个生命周期函数,分别是:页面展示时刻的onPageShow(),进行返回的时候的onBackPress(),页面消失时刻的onPageHide();

  1. onPageShow() {
  2. console.log(`${TAG} onPageShow`);
  3. }
  4. onPageHide() {
  5. console.log(`${TAG} onPageHide`);
  6. }
  7. onBackPress() {
  8. if (this.isShowToast()) {
  9. prompt.showToast({ message: $r('app.string.prompt_text'), duration: TIME });
  10. this.clickBackTimeRecord = new Date().getTime();
  11. return true;
  12. }
  13. return false;
  14. }

其中当用点击返回按钮,触发的onBackPress()函数,是可以设置返回值的,当函数返回true时,表示页面自己处理返回逻辑,不进行页面返回,返回false,由系统处理返回逻辑,默认是返回false。

ArkTS支持条件渲染,使用if/else if/else进行条件渲染,我们看一段示例代码:

  1. //ListItemComponent.ets 文件中的代码片段
  2. Column(){
  3. if(this.isRenderCircleText()){
  4. this.CircleText(this.index);
  5. }else{
  6. Text(this.index.toString())
  7. .lineHeight(ItemStyle.TEXT_LAYOUT_SIZE)
  8. .textAlign(TextAlign.Center)
  9. .width(ItemStyle.TEXT_LAYOUT_SIZE)
  10. .fontWeight(FontWeight.BOLD)
  11. .fontSize(FontSize.SMALL)
  12. }
  13. }

通过条件渲染,我们可以对排名前三名的样式做特殊处理,让1,2,3前面带上圆形的底色。

使用Foreach循环渲染自定义组件,可以方便快速生成列表类展示

  1. //代码片段来自Index.ets
  2. @Builder RankList(widthValue: Length) {
  3. Column() {
  4. List() {
  5. ForEach(this.isSwitchDataSource ? this.dataSource1 : this.dataSource2,
  6. (item, index) => {
  7. ListItem() {
  8. ListItemComponent({ index: index + 1, name: item.name, vote: item.vote,
  9. isSwitchDataSource: this.isSwitchDataSource
  10. })
  11. }
  12. }, (item, index) => item.id)
  13. }
  14. .width(WEIGHT)
  15. .height(Style.LIST_HEIGHT)
  16. .divider({ strokeWidth: Style.STROKE_WIDTH })
  17. }
  18. .padding({ left: Style.RANK_PADDING,
  19. right: Style.RANK_PADDING })
  20. .borderRadius(Style.BORDER_RADIUS)
  21. .width(widthValue)
  22. .alignItems(HorizontalAlign.Center)
  23. .backgroundColor(Color.White)
  24. }

最后,我们在了解下组件的状态管理,掌握如何基于组件的数值变化而呈现不同效果。 

效果1,当我们点击水果排行榜某一行数据的时候,被点击的行的字体颜色呈蓝色:

具体实现逻辑是通过@State装饰器修饰的变量isChange来完成的。 需要注意的是被@State修饰的变量是组件的内部数据,

  1. Text(this.name)
  2. .width(ItemStyle.LAYOUT_WEIGHT_CENTER)
  3. .fontWeight(FontWeight.BOLDER)
  4. .fontSize(FontSize.MIDDLE)
  5. .fontColor(this.isChange?ItemStyle.COLOR_BLUE:ItemStyle.COLOR_BLACK)
  6. Text(this.vote)
  7. .width(ItemStyle.LAYOUT_WEIGHT_RIGHT)
  8. .fontWeight(FontWeight.BOLDER)
  9. .fontSize(FontSize.SMALL)
  10. .fontColor(this.isChange?ItemStyle.COLOR_BLUE:ItemStyle.COLOR_BLACK)

效果二:通过标题栏右侧的刷新按钮,刷新组件内容,看不同组件之间数据变化如何进行UI更新呢?

这个效果,我们可以使用@State和@Link装饰器配合使用,来实现这一效果,在TitleCommponent组件中用@Link修饰 isRrefeshData变量,来标识水果排行榜数据的切换标识,需要注意的是@Link装饰器修饰的变量需要父组件在创建TitleCommponent的时候进行初始化。@Link装饰的变量可以父组件的@State装饰的变量建立双向数据绑定,因此对子组件的变量值修改,会同步修改父组件对应的@State修饰的变量,这里对应的就是父组件里的isSwitchDataSource变量,从而自动触发父组件的UI刷新。

  1. @Component
  2. export struct TitleComponent{
  3. @Link isRefreshData: boolean;
  4. @State title:Resource=$r('app.string.app_name');
  5. build(){
  6. Row(){
  7. Row(){
  1. @Entry
  2. @Component
  3. struct Index {
  4. @State dataSource1: RankData[] = [];
  5. @State dataSource2: RankData[] = [];
  6. // The State is used to decide whether to switch the data of RankList.
  7. @State isSwitchDataSource: boolean = true;
  8. // It will record the time of clicking back button of system navigation.
  9. private clickBackTimeRecord: number = 0;

@Link修饰的变量在父组件中必须使用引用进行初始化,这里我们通过$操作符来创建“引用” 。

 TitleComponent({ isRefreshData: $isSwitchDataSource, title: TITLE })

本帖是结合自己学习的过程的一个整理,如果您参考和学习的过程中有碰到问题,欢迎评论留言,一起学习一起进步成长!

源码下载:https://download.csdn.net/download/wangjianlong/87148688

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/92147
推荐阅读
相关标签
  

闽ICP备14008679号