开发 ArkTS HarmonyOS 开发 Melody 2023-12-26 2024-02-02 环境搭建 下载DevEcoStudio 安装 配置开发环境 环境错误处理 运行第一个程序 Hello World 应用预览 TypeScript 基本语法 变量声明 TypeScript在JavaScript的基础上加入了静态类型检查功能,因此每一个变量都有固定的数据类型。let msg: String = 'Hello World'
let
代表 声明变量的关键字,const
则代表常量msg
则为可自定义的变量名String
则为该变量的数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 let msg : String = 'Hello World' let age : number = 21.5 let finished : boolean = true let a : any = 'Bob' let u : string |number |boolean = 21 let o = {name : 'Jason' , age : 20 }console .log (o.name )console .log (o['age' ])let names : Array <String > = ['Bob' ,'Tom' ,'Jack' ]let ages : number [] = [1 ,5 ,2 ,7 ,8 ]console .log (names[0 ])
条件控制 TypeScript 与 大多数编程语言一样支持if-else
和 switch
的条件控制语句。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let num : number = 21 if (num % 2 === 1 ){ console .log (num + '是奇数' ) } else { console .log (num + '是偶数' ) } if (num > 0 ) { console .log (num + '是正数' ) }else if (num < 0 ) { console .log (num + '是负数' ) }else { console .log (num + '为零' ) }
注意: 在TypeScript
中 空字符串
、数字零
、null
、underfined
,都被认为是False
,其他值则为true
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 let grade : string = 'A' switch (grade) { case 'A' : { console .log ('优秀' ) break } case 'B' : { console .log ('合格' ) break } case 'C' : { console .log ('不合格' ) break } default : { console .log ('非法输入' ) break } }
循环迭代 TypeScript
支持 for
和 while
循环,并且为一些内置类型如 Array
提供了快捷迭代
语法。
1 2 3 4 5 6 7 8 9 10 11 12 for (let i = 0 ; i < 10 ; i++) { console .log ('输出' + i + '次' ) } let i = 1 while (i <= 10 ) { console .log ('输入' + i + '次' ) i++ }
1 2 3 4 5 6 7 8 9 10 11 12 let names : string [] = ['Jack' ,'Lucy' ]for (const i in names) { console .log (i + ':' + names[i]) } for (const name of names) { console .log (name) }
函数 TypeScript
通常利用 function
关键字来声明函数、并支持可选参数、默认参数、剪头函数等特殊语法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function sayHello (name: string ):void { console .log ('你好' + name + '!' ) } sayHello ('Jack' )function sum (x:number , y:number ):number { return x + y } let result = sum (21 ,18 )console .log ('21 + 18 = ' + result)const sayHi = (name: string ) => { console .log ('Hi' + name +'!' ) } sayHi ('Jack' )
1 2 3 4 5 6 7 8 9 function sayHello (name?: String ) { name = name ? name : '陌生人' console .log ('你好,' + name + '!' ) } sayHello ('Jack' )sayHello ()
1 2 3 4 5 6 7 function sayHello (name: string = '陌生人' ) { console .log ('你好,' + name + '!' ) } sayHello ('Jack' )sayHello ()
类和接口 TypeScript
具备面向对象变成的基本语法,例如 interface
、class
、enum
等。也具备 继承、多态等面向对象基本特征。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 enum Msg { HI = 'HI' , HELLO = 'Hello' } interface A { say (msg : Msg ):void } class B implements A { say (msg : Msg ):void { console .log (msg + ', I am B' ) } } const a :A = new B ()a.say (Msg .HI )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Rectangle { private width : number private length : number constructor (width: number , length: number ){ this .width = width this .length = length } public area (): number { return this .width * this .length } } class Square extends Rectangle { constructor (side: number ) { super (side, side) } } let s = new Square (10 )console .log ('正方形的面积为:' + s.area ())
模块开发 应用复杂时,我们可以把通用功能抽取到单独的ts中,每一个文件都是模块(module)。模块可以相互加载,提高代码复用性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 export class Rectangle { private width : number private length : number constructor (width: number , length: number ){ this .width = width this .length = length } } export function area (rec: Rectangle ):number { return rec.width * rec.length }
1 2 3 4 5 6 import {Rectangle , area} from '../Rectangle' let r = new Rectangle (10 ,20 )console .log ('面积为:' + area (r))
快速入门 ArkUI基本结构 这个示例中所包含的ArkTS声明式开发范式的基本组成说明如下:
用来装饰类、结构体、方法以及变量,赋予其特殊的含义,如上述示例中 @Entry
、 @Component
、 @State
都是装饰器。具体而言, @Component
表示这是个自定义组件; @Entry
则表示这是个入口组件; @State
表示组件中的状态变量,此状态变化会引起 UI 变更。
可复用的 UI 单元,可组合其它组件,如上述被 @Component
装饰的 struct Hello
。
声明式的方式来描述 UI 的结构,如上述 build()
方法内部的代码块。
框架中默认内置的基础和布局组件,可直接被开发者调用,比如示例中的 Column
、Text
、Divider
、Button
。
用于添加组件对事件的响应逻辑,统一通过事件方法进行设置,如跟随在Button后面的onClick()。
用于组件属性的配置,统一通过属性方法进行设置,如fontSize()
、width()
、height()
、color()
等,可通过链式调用的方式设置多项属性。 从UI框架的需求角度,ArkTS
在TS
的类型系统的基础上,做了进一步的扩展:定义了各种装饰器、自定义组件和UI描述机制 ,再配合UI开发框架中的UI内置组件、事件方法、属性方法等共同构成了应用开发的主体。在应用开发中,除了UI的结构化描述之外,还有一个重要的方面:状态管理 。如上述示例中,用 @State 装饰过的变量 myText ,包含了一个基础的状态管理机制,即 myText 的值的变化会自动触发相应的 UI 变更 (Text组件)。ArkUI 中进一步提供了多维度的状态管理机制 。和 UI 相关联的数据,不仅可以在组件内使用,还可以在不同组件层级间传递,比如父子组件之间,爷孙组件之间,也可以是全局范围内的传递,还可以是跨设备传递。另外,从数据的传递形式来看,可分为只读的单向传递和可变更的双向传递 。开发者可以灵活的利用这些能力来实现数据和 UI 的联动。 总体而言,ArkUI开发框架通过扩展成熟语言、结合语法糖或者语言原生的元编程能力、以及UI组件、状态管理等方面设计了统一的UI开发范式,结合原生语言能力共同完成应用开发。这些构成了当前ArkTS基于TS的主要扩展。
ArkUI组件 - Image 组件
使用Image组件并设置图片源
Image(src: string|PixelMap|Resource)
string
格式,通常用来加载网络图片,需要申请网络权限:ohos.permission.INTERNET
Image('https://xxx.png')
b. PixelMap
格式,可以加载像素图,常用在图片编辑中Image(pixelMapObject)
c. Resource
格式,可以加载本地图片,推荐使用Image($r('app.media.mate60'))
Image($rawfile('mate60.png'))
添加图片属性1 2 3 4 5 Image ($r('app.media.icon' )) .width (100 ) .height (100 ) .borderRadius (10 ) .interpolation (ImageInterpolation .HIGH )
ArkUI组件 - Text
使用Text组件来声明文本内容
Text(content?: string|Resource)
a. string
格式,直接书写文本内容Text('图片宽度')
b. Resource
资源,读取本地资源文件Text($r('app.string.width_label'))
1 2 3 4 Text ('' ) .fontSize (24 ) .fontWidth (FontWeight .Bolder ) .fontColor ('#666' )
ArkUI组件 - TextInput
声明 TextInput
组件:
TextInput({placeholder?: ResourceStr, text?: ResourceStr})
a. placeholder
输入框中无输入时提示的文本TextInput({placeholder: '请输入账号或手机号'})
b. text
输入框当前的文本内容TextInput({text: 'it'})
添加属性和事件1 2 3 4 5 6 7 8 TextInput ({text : '当前输入文本' }) .width (150 ) .height (50 ) .backgroundColor ('#fff' ) .type (InputType .password ) .onChange ((value:string ) => { this .imageWidth = value })
声明 Button
组件,label是按钮文字
Button(label?: ResourceStr)
a.文字性按钮Button('点我)
b.自定义按钮Button{
Image($r('app.meida.search)).width(20).margin(10)
}
添加属性和事件1 2 3 4 5 6 7 Button ('点我' ) .width (100 ) .height (30 ) .type (ButtonType .Normal ) .onClick (() => { })
ArkUI组件 - Slider
声明Silder
滑动条租金
Silder(options?:SliderOptions)
添加属性和事件1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Slider ({ min : 0 , max : 200 , value : 30 , step : 10 , style : SliderStyle .OutSet , direction : Axis .Horizontal , reverse : false }) .width ('90%' ) .showTips (true ) .blockColor ('#36D' ) .onChange (value => { })
ArkUI组件 - Column 和 Row
属性方法名
说明
参数
justifyContent
设置子元素
在主轴
的对齐格式
FlexAlign
枚举
alignItems
设置子元素
在交叉轴
的对齐格式
Row
容器使用VerticalAlign
枚举
Column
容器使用HorizontalAlign
枚举
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Entry @Component struct Index { build ( ){ Column ({space : 20 }){ Text ('item1' ) Text ('item2' ) Text ('item3' ) Text ('item4' ) } .width ('100%' ) .height ('100%' ) .justifyContent (FlexAlign .Center ) .alignItems (HorizontalAlign .Center ) } }
关于子元素
在主轴
方向的对齐方向 属性名:justifyContent
参数:FlexAlign
枚举 关于子元素
在交叉轴
方向的对齐方向 属性名:alignItems
参数:Row
容器使用VerticalAlign
枚举Column
容器使用HorizontalAlign
枚举
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 @Entry @Component struct Demo { @State imageWidth : number = 200 build ( ){ Column (){ Row (){ Image ($r('app.media.mate60' )) .width (this .imageWidth ) } .width ('100%' ) .height (400 ) .justifyContent (FlexAlign .Center ) Row (){ Text ('图片宽度:' ) .fontSize (22 ) .fontWeight (FontWeight .Bolder ) .fontColor ('#666' ) TextInput ({text : this .imageWidth .toFixed (0 )}) .width (200 ) .onChange ((value:string ) => { this .imageWidth = parseInt (value) }) } .width ('100%' ) .justifyContent (FlexAlign .SpaceBetween ) .padding ({left : 20 , right : 20 ,bottom : 10 }) Divider () .width ('90%' ) Row (){ Button ('缩小' ) .width (80 ) .type (ButtonType .Normal ) .onClick (() => { if (this .imageWidth && this .imageWidth > 10 ) { this .imageWidth -= 10 } }) Button ('放大' ) .width (80 ) .type (ButtonType .Normal ) .onClick (() => { if (this .imageWidth && this .imageWidth < 300 ) { this .imageWidth += 10 } }) } .margin ({top : 20 }) .width ('100%' ) .justifyContent (FlexAlign .SpaceEvenly ) Slider ({ min : 0 , max : 300 , value : this .imageWidth , step : 10 }) .width ('100%' ) .blockColor ('#36D' ) .trackThickness (7 ) .showTips (true ) .onChange (value => { this .imageWidth = value }) .margin ({top : 200 }) } .height ('100%' ) .width ('100%' ) } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 class Item { name : string image : ResourceStr price : number discount : number constructor (name: string , image: ResourceStr, price: number , discount: number = 0 ) { this .name = name this .image = image this .price = price this .discount = discount } } @Entry @Component struct Index { private items : Array <Item > = [ new Item ('华为Mate60' , $r('app.media.mate60' ),6999 , 500 ), new Item ('MateBookProX' , $r('app.media.mateBookProX' ),13999 ), new Item ('WatchGT4' , $r('app.media.watchGT4' ),1438 ), new Item ('FreeBuds Pro3' , $r('app.media.freeBudsPro3' ),1499 ), new Item ('Mate X5' , $r('app.media.mateX5' ),12999 ) ] build ( ){ Column ({space : 8 }){ Row (){ Text ('商品列表' ) .fontSize (30 ) .fontWeight (FontWeight .Bold ) } .width ('100%' ) .margin ({bottom : 20 }) Row ({space : 10 }){ Image ($r('app.media.mate60' )) .width (100 ) Column ({space : 4 }){ Text ('华为Mate60' ) .fontSize (20 ) .fontWeight (FontWeight .Bold ) Text ('¥ 6999' ) .fontColor ('#F36' ) .fontSize (18 ) } .height ('100%' ) .alignItems (HorizontalAlign .Start ) } .backgroundColor ('#fff' ) .width ('100%' ) .borderRadius (20 ) .height (120 ) .padding (10 ) } .width ('100%' ) .height ('100%' ) .backgroundColor ('#EFEFEF' ) .padding (20 ) } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 class Item { name : string image : ResourceStr price : number discount : number constructor (name: string , image: ResourceStr, price: number , discount: number = 0 ) { this .name = name this .image = image this .price = price this .discount = discount } } @Entry @Component struct Index { private items : Array <Item > = [ new Item ('华为Mate60' , $r('app.media.mate60' ),6999 , 500 ), new Item ('MateBookProX' , $r('app.media.mateBookProX' ),13999 ), new Item ('WatchGT4' , $r('app.media.watchGT4' ),1438 ), new Item ('FreeBuds Pro3' , $r('app.media.freeBudsPro3' ),1499 ), new Item ('Mate X5' , $r('app.media.mateX5' ),12999 ) ] build ( ){ Column ({space : 8 }){ Row (){ Text ('商品列表' ) .fontSize (30 ) .fontWeight (FontWeight .Bold ) } .width ('100%' ) .margin ({bottom : 20 }) ForEach ( this .items , (item: Item ) => { Row ({space : 10 }){ Image ((item.image )) .width (100 ) Column ({space : 4 }){ Text (item.name ) .fontSize (20 ) .fontWeight (FontWeight .Bold ) Text ('¥ ' + item.price ) .fontColor ('#F36' ) .fontSize (18 ) } .height ('100%' ) .alignItems (HorizontalAlign .Start ) } .backgroundColor ('#fff' ) .width ('100%' ) .borderRadius (20 ) .height (120 ) .padding (10 ) } ) } .width ('100%' ) .height ('100%' ) .backgroundColor ('#EFEFEF' ) .padding (20 ) } }
完成最终效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 class Item { name : string image : ResourceStr price : number discount : number constructor (name: string , image: ResourceStr, price: number , discount: number = 0 ) { this .name = name this .image = image this .price = price this .discount = discount } } @Entry @Component struct Index { private items : Array <Item > = [ new Item ('华为Mate60' , $r('app.media.mate60' ),6999 , 500 ), new Item ('MateBookProX' , $r('app.media.mateBookProX' ),13999 ), new Item ('WatchGT4' , $r('app.media.watchGT4' ),1438 ), new Item ('FreeBuds Pro3' , $r('app.media.freeBudsPro3' ),1499 ), new Item ('Mate X5' , $r('app.media.mateX5' ),12999 ) ] build ( ){ Column ({space : 8 }){ Row (){ Text ('商品列表' ) .fontSize (30 ) .fontWeight (FontWeight .Bold ) } .width ('100%' ) .margin ({bottom : 20 }) ForEach ( this .items , (item: Item ) => { Row ({space : 10 }){ Image ((item.image )) .width (100 ) Column ({space : 4 }){ if (item.discount ){ Text (item.name ) .fontSize (20 ) .fontWeight (FontWeight .Bold ) Text ('原价:¥ ' + item.price ) .fontColor ('#F36' ) .fontSize (18 ) .fontColor ('#666' ) .decoration ({type : TextDecorationType .LineThrough }) Text ('折扣价:¥ ' + (item.price - item.discount )) .fontColor ('#F36' ) .fontSize (18 ) Text ('补贴信息:¥ ' + item.discount ) .fontColor ('#F36' ) .fontSize (18 ) } else { Text (item.name ) .fontSize (20 ) .fontWeight (FontWeight .Bold ) Text ('¥ ' + item.price ) .fontColor ('#F36' ) .fontSize (18 ) } } .height ('100%' ) .alignItems (HorizontalAlign .Start ) } .backgroundColor ('#fff' ) .width ('100%' ) .borderRadius (20 ) .height (120 ) .padding (10 ) } ) } .width ('100%' ) .height ('100%' ) .backgroundColor ('#EFEFEF' ) .padding (20 ) } }
ArkUI组件 - List
列表 (List) 是一种复杂容器,具备以下特点:
列表项(ListItem) 数量过多超出屏幕后,会自动提供滚动功能
列表项(ListItem) 既可以纵向排列,也可以横向排列
1 2 3 4 5 6 List (space : 10 }){ ForEach ([1 ,2 ,3 ,4 ],item => { }) } .width ('100%' )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 class Item { name : string image : ResourceStr price : number discount : number constructor (name: string , image: ResourceStr, price: number , discount: number = 0 ) { this .name = name this .image = image this .price = price this .discount = discount } } @Entry @Component struct Index { private items : Array <Item > = [ new Item ('华为Mate60' , $r('app.media.mate60' ),6999 , 500 ), new Item ('MateBookProX' , $r('app.media.mateBookProX' ),13999 ), new Item ('WatchGT4' , $r('app.media.watchGT4' ),1438 ), new Item ('FreeBuds Pro3' , $r('app.media.freeBudsPro3' ),1499 ), new Item ('Mate X5' , $r('app.media.mateX5' ),12999 ), new Item ('Mate X5' , $r('app.media.mateX5' ),12999 ), new Item ('Mate X5' , $r('app.media.mateX5' ),12999 ) ] build ( ){ Column ({space : 8 }){ Row (){ Text ('商品列表' ) .fontSize (30 ) .fontWeight (FontWeight .Bold ) } .width ('100%' ) .height (30 ) .margin ({bottom : 20 }) List ({space : 9 }){ ForEach ( this .items , (item: Item ) => { ListItem (){ Row ({space : 10 }){ Image ((item.image )) .width (100 ) Column ({space : 4 }){ if (item.discount ){ Text (item.name ) .fontSize (20 ) .fontWeight (FontWeight .Bold ) Text ('原价:¥ ' + item.price ) .fontColor ('#F36' ) .fontSize (18 ) .fontColor ('#666' ) .decoration ({type : TextDecorationType .LineThrough }) Text ('折扣价:¥ ' + (item.price - item.discount )) .fontColor ('#F36' ) .fontSize (18 ) Text ('补贴信息:¥ ' + item.discount ) .fontColor ('#F36' ) .fontSize (18 ) } else { Text (item.name ) .fontSize (20 ) .fontWeight (FontWeight .Bold ) Text ('¥ ' + item.price ) .fontColor ('#F36' ) .fontSize (18 ) } } .height ('100%' ) .alignItems (HorizontalAlign .Start ) } .backgroundColor ('#fff' ) .width ('100%' ) .borderRadius (20 ) .height (120 ) .padding (10 ) } } ) } .width ('100%' ) .layoutWeight (1 ) } .width ('100%' ) .height ('100%' ) .backgroundColor ('#EFEFEF' ) .padding (20 ) } }
ArkUI组件 - 自定义组件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 class Item { name : string image : ResourceStr price : number discount : number constructor (name: string , image: ResourceStr, price: number , discount: number = 0 ) { this .name = name this .image = image this .price = price this .discount = discount } } import {Header } from '../components/Header' @Builder function itemCard (item:Item ){ Row ({space : 10 }){ Image ((item.image )) .width (100 ) Column ({space : 4 }){ if (item.discount ){ Text (item.name ) .fontSize (20 ) .fontWeight (FontWeight .Bold ) Text ('原价:¥ ' + item.price ) .fontColor ('#F36' ) .fontSize (18 ) .fontColor ('#666' ) .decoration ({type : TextDecorationType .LineThrough }) Text ('折扣价:¥ ' + (item.price - item.discount )) .fontColor ('#F36' ) .fontSize (18 ) Text ('补贴信息:¥ ' + item.discount ) .fontColor ('#F36' ) .fontSize (18 ) } else { Text (item.name ) .fontSize (20 ) .fontWeight (FontWeight .Bold ) Text ('¥ ' + item.price ) .fontColor ('#F36' ) .fontSize (18 ) } } .height ('100%' ) .alignItems (HorizontalAlign .Start ) } .backgroundColor ('#fff' ) .width ('100%' ) .borderRadius (20 ) .height (120 ) .padding (10 ) } @Entry @Component struct Index { private items : Array <Item > = [ new Item ('华为Mate60' , $r('app.media.mate60' ),6999 , 500 ), new Item ('MateBookProX' , $r('app.media.mateBookProX' ),13999 ), new Item ('WatchGT4' , $r('app.media.watchGT4' ),1438 ), new Item ('FreeBuds Pro3' , $r('app.media.freeBudsPro3' ),1499 ), new Item ('Mate X5' , $r('app.media.mateX5' ),12999 ) ] build ( ){ Column ({space : 8 }){ Header ({title : '商品列表' }) .margin ({bottom : 10 }) ForEach ( this .items , (item: Item ) => { itemCard (item) } ) } .width ('100%' ) .height ('100%' ) .backgroundColor ('#EFEFEF' ) .padding (20 ) } }
@Component
export struct Header{
private title: ResourceStr;
build(){
Row(){
Text(this.title)
.fontSize(30)
.fontWeight(FontWeight.Bold)
Blank()
Image($r('app.media.ic_public_refresh'))
.width(30)
}
.width('100%')
.height(30)
}
}