# HarmonyOSProject **Repository Path**: chen-fengping-mm/harmony-osproject ## Basic Information - **Project Name**: HarmonyOSProject - **Description**: B站HarmonyOS教程复刻:【全网首发黑马程序员鸿蒙 HarmonyOS NEXT星河版零基础入门到实战,零基础也能快速入门鸿蒙开发教程】 https://www.bilibili.com/video/BV14t421W7pA/?p=41&share_source=copy_web&vd_source=2477afc28febe78f5770e7aa6c5f40e1 - **Primary Language**: TypeScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 3 - **Created**: 2025-01-02 - **Last Updated**: 2025-01-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # HarmonyOS NEXT ## 构建界面 ### ArkTS #### 基础快速入门 ```TypeScript //这是一行注释 /* * 这是一段注释 * */ console.log('Hello World') // @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { } .height('100%') .width('100%') } } ``` #### 认识和存储数据 ```TypeScript //声明一个string类型的变量 let variableName1: string = 'Hello World'; let variableName2: String = 'Hello World'; //String 可以大写 let variableName3 = 'Hello World'; //声明一个number类型的变量 let variableName4: number = 12; let variableName5: Number = 12; let variableName6 = 12; //声明一个boolean类型的变量 let variableName7: boolean = true; let variableName8: Boolean = true; let variableName9 = true; console.log('variableName1', variableName1) console.log('variableName2', variableName2) console.log('variableName3', variableName3) console.log('variableName4', variableName4) console.log('variableName5', variableName5) console.log('variableName6', variableName6) console.log('variableName7', variableName7) console.log('variableName8', variableName8) console.log('variableName9', variableName9) ``` #### 常量和变量的命名规则 ```TypeScript const constantName1: number = 10; const constantName2: string = '10'; const constantName3: boolean = false; const constantName4 = 10; const constantName5 = '10'; const constantName6 = false; console.log('constantName1', constantName1); console.log('constantName2', constantName2); console.log('constantName3', constantName3); console.log('constantName4', constantName4); console.log('constantName5', constantName5); console.log('constantName6', constantName6); ``` #### 数组 ```TypeScript let arrayName: string[] = ['Name1', 'Name2', 'Name3']; console.log('Name1',arrayName[0]); console.log('arrayName',arrayName);//遍历数组 ``` #### 函数 ```TypeScript function Func001() { console.log('五角星','*') console.log('五角星','**') console.log('五角星','***') console.log('五角星','****') } function Func002(name?: string) { if (name == undefined) { console.log('Hello') } else { console.log('Hello',name); } } function Func003(x: number = 0, y: number = 0): number { return x + y; } Func001(); Func002(); Func002('001'); console.log('Func003() = ', Func003()) ``` #### 函数的完整写法 略,同上 #### 箭头函数——`lambda`函数 * 箭头函数的返回类型可以省略;省略时,返回类型通过函数体推断。表达式可以指定为箭头函数,使表达更简短,因此以下两种表达方式是等价的 ```TypeScript let sum1 = (x: number, y: number) => { return x + y; } let sum2 = (x: number, y: number) => x + y ``` ```TypeScript let funcAdd1 = (x: number = 0, y: number = 0): number => { return x + y; } let funcAdd2 = (x: number = 0, y: number = 0) => x + y; console.log('funcAdd1(10, 10) =', funcAdd1(10, 10)); console.log('funcAdd2() =', funcAdd2()); ``` #### 接口`interface` ```TypeScript //声明一个接口 interface Person { name: string age: number weight: number }; //实例化 let p1: Person = { name: '张三', age: 18, weight: 90 } let p2: Person = { name: '李四', age: 20, weight: 98 } console.log('p1.name =', p1.name); console.log('p1.age =', p1.age); console.log('p1.weight =', p1.weight); console.log('p2.name =', p2.name); console.log('p2.age =', p2.age); console.log('p2.weight =', p2.weight); ``` #### 接口`interface`的函数 ```TypeScript interface Person { name: string; skill: string; personAbility: () => void; //声明接口的函数 }; let p1: Person = { name: '张三', skill: 'dance', personAbility: () => { //定义接口的函数 console.log('调用p1.personAbility'); } } p1.personAbility(); //调用接口的函数 ``` #### 联合类型 ```TypeScript let score: number | string = 0;//score变量可存放number值,也可以存放string值 score = 100; console.log('score =', score);//score = 100 score = '优秀'; console.log('score =', score);//score = 优秀 let sex: 'Man' | 'Women' = 'Man';//sex变量的值仅可为'Man'或'Women' sex = 'Women'; console.log('sex =', sex);//sex =Women ``` #### 枚举 ```TypeScript enum ColorSet { White = 0xFF, Grey = 0x7F, Black = 0x00 }; let colorBad = ColorSet.White; console.log('colorBad =', colorBad); ``` ### ArkUI #### 界面开发布局思路 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Text('小说简介'); Row() { Text('都市 '); Text('生活 '); Text('男频 '); Text('情感'); } } } .height('100%') .width('100%') } } ``` #### 组件的属性方法 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Text('小说简介') .width('100%') //设置组件宽度 .height(40) //设置组件高度 // .backgroundColor(Color.Pink) //设置组件背景颜色 .fontSize(20) //设置字体字号 .fontWeight(FontWeight.Bold) //设置字体样式 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.Gray) } .width('100%') } .width('100%') .backgroundColor(Color.White) } .height('100%') .width('100%') } } ``` #### 字体颜色 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Text('HarmonyOS') .width('100%') .height(40) .fontSize(24) Row() { Text('置顶 ') .fontColor('#df3c50') Text('新华社 ') .fontColor('#a1a1a1') Text('4680评论') .fontColor('#a1a1a1') } .width('100%') } .width('100%') } .height('100%') .width('100%') } } ``` #### 文本溢出省略号、行高 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Text('HarmonyOS开发初体验') .width('100%') .lineHeight(50)//行高 .fontSize(20) .fontWeight(FontWeight.Bold) Text('HarmonyOS开发初体验方舟开发框架(简称ArkUl)为HarmonyOS应用的UI开发提供了完整的基础设施,包括简洁的U语法、丰富的UI功能(组件、布局、动画以及交互事件),以及实时界面预览工具等,可以支持开发者进行可视化界面开发。') .width('100%') .lineHeight(24) .textOverflow({ overflow: TextOverflow.Ellipsis })//文本溢出时,显示省略号`...`,未设置maxLines则无效 // .textOverflow({ overflow: TextOverflow.None })//文本溢出时,直接忽略后续文本 // .textOverflow({ overflow: TextOverflow.Clip })//文本溢出时,直接裁切后续文本,不再显示 // .textOverflow({ overflow: TextOverflow.MARQUEE })//文本溢出时,滚动播放全文,但最大行数不再受其影响 .maxLines(2)//设置最大行数 } .height('100%') .width('100%') } .height('100%') .width('100%') } } ``` #### 图片组件 ```TypeScript /* 本地图片存放路径 .\entry\src\main\resources\base\media */ @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { // Image('URL') //网络图片加载方式 Image($r('app.media.Image2')) //本地图片加载方式 .width(200) Text('耐克龙年限定款!!') .width(200) Row() { Image($r('app.media.Image1')) .width(20) Text('令人脱发的代码') } .width(200) } } .height('100%') .width('100%') } } ``` #### 输入框和按钮 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column({ space: 10 }) { //space 组件间距 TextInput({ //输入组件 placeholder: '请输入用户名' //提示文本 }) TextInput({ placeholder: '请输入密码' }) .type(InputType.Password) //输入类型-密码类型 Button('登录') //按钮组件 .width(200) } .width('100%') } .height('100%') .width('100%') } } ``` #### 综合实战-华为登录 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column({ space: 15 }) { //Logo Image($r('app.media.Image1')) .width(50) //用户名输入框 TextInput({ placeholder: '请输入用户名' }) //密码输入框 TextInput({ placeholder: '请输入密码' }) .type(InputType.Password) //登录按钮 Button('登录') .width('100%') Row({ space: 15 }) { //注册文本 Text('前往注册') //忘记密码 Text('忘记密码') } } .width('100%') .padding(20) //给组件添加内边距 } .height('100%') .width('100%') } } ``` #### SVG图标 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Image($r('app.media.Image1')) .width(100) .fillColor(Color.Red)//修改SVG文件颜色 } .width('100%') } .height('100%') .width('100%') } } //https://developer.huawei.com/consumer/cn/design/harmonyos-symbol/ ``` #### 内边距padding ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Text('内边距padding') .width(200) .backgroundColor(Color.Gray) .padding(20)//组件内部的四周都存在40的边距 Text('---------------------------------') Text('内边距padding') .width(200) .backgroundColor(Color.Gray) .padding({ //单独设置四周的边距 left: 20, right: 20, top: 10, bottom: 10 }) } .width('100%') } .height('100%') .width('100%') } } ``` #### 外边距margin ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Text('外边距margin') .backgroundColor(Color.Pink) .margin(20)//组件外部的四周都存在20的边距 Text('---------------------------------') Text('外边距margin') .backgroundColor(Color.Pink) .margin({ //单独设置四周的边距 left: 20, right: 20, top: 10, bottom: 10 }) } .width('100%') .backgroundColor(Color.Gray) } .height('100%') .width('100%') } } ``` #### 综合案例-QQ音乐登录 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Image($r('app.media.Image1')) .width(80) .margin({ bottom: 10 }) Text('大王叫我来巡山') .margin({ bottom: 15 }) Button('QQ登录') .width('100%') .margin(10) Button('微信登录') .width('100%') .backgroundColor('#ddd') .fontColor(Color.Black) } .width('100%').height('100%') .padding(20) } .height('100%') .width('100%') } } ``` #### 边框border ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Text('边框border') //四条边框设置方式 .border({ width: 1, //边框线条宽度,必须设置 color: Color.Black, //边框线条颜色 style: BorderStyle.Solid //边框线条样式,实线 // style: BorderStyle.Dotted //边框线条样式,点线 // style: BorderStyle.Dashed //边框线条样式,虚线 }) .height(40) .margin(20) .padding(10) Text('边框border') //单独设置各条边的边框 .border({ width: { left: 5, right: 5 }, color: { left: Color.Blue, right: Color.Green}, style: { left: BorderStyle.Dotted, right: BorderStyle.Dashed} }) .height(40) .margin(20) .padding(10) } .width('100%') } .height('100%') .width('100%') } } ``` #### 设置组件圆角borderRadius ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Text('设置组件圆角borderRadius') //四个角同时设置圆角设置方式 .borderRadius(5) .height(40) .margin(20) .padding(10) .backgroundColor(Color.Pink) Text('设置组件圆角borderRadius') //单独设置圆角设置方式 .borderRadius({ topLeft: 20, bottomRight: 20 }) .height(40) .margin(20) .padding(10) .backgroundColor(Color.Pink) } .width('100%') } .height('100%') .width('100%') } } ``` #### 特殊形状的圆角设置 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { // 正圆形组件 要求宽高一样,圆角值为宽/高的一半 Text('正圆形组件') .borderRadius(50) .height(100).width(100) .margin(20) .padding(10) .backgroundColor(Color.Pink) // 胶囊体组件,要求宽高不同,圆角值为宽或高的一半 Text('胶囊体组件') //单独设置圆角设置方式 .borderRadius(50) .height(200).width(100) .margin(20) .padding(10) .backgroundColor(Color.Pink) } .width('100%') } .height('100%') .width('100%') } } ``` #### 背景属性-背景图片 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Text('给Text组件添加图片背景') .backgroundColor(Color.Pink) .width('100%').height(400) .backgroundImage($r('app.media.Image1'), ImageRepeat.NoRepeat)//给组件添加图片背景 平铺方式-不平铺-默认值,可省略 // .backgroundImage($r('app.media.Image1'), ImageRepeat.X)//给组件添加图片背景 平铺方式-X轴平铺 // .backgroundImage($r('app.media.Image1'), ImageRepeat.Y)//给组件添加图片背景 平铺方式-Y轴平铺 // .backgroundImage($r('app.media.Image1'), ImageRepeat.XY)//给组件添加图片背景 平铺方式-整个组件平铺 } .width('100%') .height('100%') // .backgroundColor(Color.Pink) } .height('100%') .width('100%') } } ``` #### 背景属性-图片位置 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Text('给Text组件添加图片背景') .backgroundColor(Color.Pink) .width('100%').height(400) .backgroundImage($r('app.media.Image1'), ImageRepeat.NoRepeat) .backgroundImagePosition({ x: 200, y: 50 })//设置背景图片位置 // .backgroundImagePosition(Alignment.TopStart)//设置背景图片位置为顶端起始位置 // .backgroundImagePosition(Alignment.Top)//设置背景图片位置为顶端居中位置 // .backgroundImagePosition(Alignment.TopEnd)//设置背景图片位置为顶端末尾位置 // .backgroundImagePosition(Alignment.Start)//设置背景图片位置为中间起始位置 // .backgroundImagePosition(Alignment.Center)//设置背景图片位置为组件中心位置 // .backgroundImagePosition(Alignment.End)//设置背景图片位置为中间末尾位置 // .backgroundImagePosition(Alignment.BottomStart)//设置背景图片位置为底端起始位置 // .backgroundImagePosition(Alignment.Bottom)//设置背景图片位置为底端居中位置 // .backgroundImagePosition(Alignment.BottomEnd)//设置背景图片位置为底端末尾位置 } .width('100%') .height('100%') } .height('100%') .width('100%') } } ``` #### 背景属性-背景尺寸大小 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Text('给Text组件添加图片背景') .backgroundColor(Color.Pink) .width('100%').height(400) .backgroundImage($r('app.media.Image1'), ImageRepeat.NoRepeat) // .backgroundImageSize({ width: 40, height: 60 })//设置组件背景图片的尺寸 // .backgroundImageSize(ImageSize.Auto)//默认,原图尺寸 // .backgroundImageSize(ImageSize.Cover)//根据组件尺寸,铺满整个组件 // .backgroundImageSize(ImageSize.Contain)//等比例铺满整个组件 } .width('100%') .height('100%') } .height('100%') .width('100%') } } ``` #### 线性布局 ```TypeScript import { ResizeDirection } from '@kit.TestKit'; @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Text('组件1').width(200).height(50).backgroundColor(Color.Pink).border({width: 1}) Text('组件2').width(200).height(50).backgroundColor(Color.Pink).border({width: 1}) Text('组件3').width(200).height(50).backgroundColor(Color.Pink).border({width: 1}) Text('组件4').width(200).height(50).backgroundColor(Color.Pink).border({width: 1}) } .width('100%').height('100%') .backgroundColor(Color.Gray) // .justifyContent(FlexAlign.Start)//在组件主轴方向,在正方向排布,默认 .justifyContent(FlexAlign.Center)//在组件主轴方向,居中排布 // .justifyContent(FlexAlign.End)//在组件主轴方向,在反方向排布 // .justifyContent(FlexAlign.SpaceBetween)//在组件主轴方向,两端对齐,中间平均分布 // .justifyContent(FlexAlign.SpaceAround)//在组件主轴方向,每个组件的主轴边距相同 // .justifyContent(FlexAlign.SpaceEvenly)//在组件主轴方向,每个组件均匀分布 } .height('100%') .width('100%') } } ``` #### 综合案例-个人中心 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Row() { Image($r('app.media.Image1')) .width(30) Text('个人中心') Image($r('app.media.Image2')) .width(24) } .width('100%') .height(40) .backgroundColor(Color.White) .justifyContent(FlexAlign.SpaceBetween) .padding({ left: 10, right: 10 }) } .backgroundColor('#ccc') .width('100%').height('100%') } .height('100%') .width('100%') } } ``` #### 交叉轴对齐方式 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Column() { Text('组件1').border({ width: 1 }).padding({ left: 10, right: 10 }).backgroundColor(Color.Pink); Text('组件2').border({ width: 1 }).padding({ left: 10, right: 10 }).backgroundColor(Color.Pink); Text('组件3').border({ width: 1 }).padding({ left: 10, right: 10 }).backgroundColor(Color.Pink); } .backgroundColor(Color.Blue) .width('100%') .alignItems(HorizontalAlign.Start) //其交叉轴(横轴)的对齐方式为靠起始 // .alignItems(HorizontalAlign.End) //其交叉轴(横轴)的对齐方式为靠结尾 // .alignItems(HorizontalAlign.Center) //其交叉轴的对齐方式为居中-默认值 Row() { Text('组件4').border({ width: 1 }).padding({ left: 10, right: 10 }).backgroundColor(Color.Pink); Text('组件5').border({ width: 1 }).padding({ left: 10, right: 10 }).backgroundColor(Color.Pink); Text('组件6').border({ width: 1 }).padding({ left: 10, right: 10 }).backgroundColor(Color.Pink); } .backgroundColor(Color.Green) .height(100) // .alignItems(VerticalAlign.Top) //其交叉轴(纵轴)的对齐方式为靠顶端 // .alignItems(VerticalAlign.Bottom) //其交叉轴(纵轴)的对齐方式为靠底端 .alignItems(VerticalAlign.Center) //其交叉轴(纵轴)的对齐方式为居中-默认值 } .height('100%') .width('100%') } .height('100%') .width('100%') } } ``` #### 综合案例-得物列表项 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Row() { Column({ space: 8 }) { Text('玩一玩') .fontSize(20) .fontWeight(FontWeight.Bold) Text('签到兑礼 | 超多大奖 超好玩') .fontSize(12) .fontColor('#999') } .alignItems(HorizontalAlign.Start) .width('70%') .padding(10) Row({ space: 8 }) { Image($r('app.media.Image1')) .width(50) .backgroundColor('#efefef') .borderRadius(5) Image($r('app.media.Image2')) .width(20) .fillColor('#999') } } .justifyContent(FlexAlign.SpaceBetween) .padding({ left: 15, right:15 }) .width('100%').height(80) .backgroundColor('#fff') } .height('100%') .width('100%') } } ``` #### 自适应伸缩 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { //layoutWeight 按照权重分配`剩余空间` Row() { Text('组件1').padding({ left: 10, right: 10 }).border({ width: 1 }) .layoutWeight(1) //将主轴分为1+2+2份,该组件占1份 Text('组件2').padding({ left: 10, right: 10 }).border({ width: 1 }) .layoutWeight(2) //将主轴分为1+2+2份,该组件占2份 Text('组件3').padding({ left: 10, right: 10 }).border({ width: 1 }) .layoutWeight(2) //将主轴分为1+2+2份,该组件占2份 } .margin({ bottom: 20 }) Row() { Text('组件4').padding({ left: 10, right: 10 }).border({ width: 1 }) .layoutWeight(1) //剩余空间均分配给该组件 Text('组件5').padding({ left: 10, right: 10 }).border({ width: 1 }) .width(150) Text('组件6').padding({ left: 10, right: 10 }).border({ width: 1 }) .width(70) } } .width('100%').height(100) .backgroundColor('#ccc') .padding(10) } .height('100%') .width('100%') } } ``` #### 综合案例-得物卡片 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column({ space: 10 }) { Column({ space: 20 }) { Image($r('app.media.Image1')).width('100%').borderRadius(10) Text('今晚吃这个 | 每日艺术分享 No.43').fontSize(25).fontWeight(600) } .width('100%') .padding(10) Row() { Row({ space: 5 }) { Image($r('app.media.Image2')).width(30).height(30).borderRadius(15) Text('插画师分享聚集地').fontColor('#ccc') } Row({ space: 5 }) { Image($r('app.media.Image3')).width(15).fillColor('#ccc') Text('2300').fontColor('#ccc') } } .width('100%') .padding(20) .justifyContent(FlexAlign.SpaceBetween) } .width('100%') } .height('100%') .width('100%') } } ``` #### 综合案例-京东登录 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { //顶部 Row() { Image($r('app.media.Image2')).width(20) Text('帮助').fontSize(16) } .width('100%') .justifyContent(FlexAlign.SpaceBetween) //Logo Image($r('app.media.Image5')).width(250).height(250) //中部区域 Column() { //国家/地区 中国(+86) Row() { Text('国家/地区').layoutWeight(1).fontColor('#666') Row() { Text('中国(+86)').margin({ right: 5 }).fontColor('#666') Image($r('app.media.Image7')).width(16).fillColor('#666') } } .width('100%') .height(40) .padding({ left: 15, right: 10 }) .backgroundColor(Color.White) .borderRadius(20) .justifyContent(FlexAlign.SpaceBetween) } //手机号输入框 TextInput({ placeholder: '请输入手机号' }) .placeholderColor('#666') .margin({ top: 20 }) .backgroundColor(Color.White) Row() { Checkbox().width(10) //复选框 //提示文本 Text() { Span('我已阅读并同意') Span('《京东隐私政策》').fontColor('#3274f6') Span('《京东用户服务协议》').fontColor('#3274f6') Span('未注册的手机号讲自动创建京东账号') } .fontSize(12) .fontColor('#666') .lineHeight(20) } .margin({ top: 20 }) .alignItems(VerticalAlign.Top) //登录按钮 Button('登录').width('100%').backgroundColor('#bf2838').margin({ top: 20 }) //登录异常处理 Row({ space: 25 }) { Text('新用户注册').fontSize(14).fontColor('#666') Text('账户密码登录').fontSize(14).fontColor('#666') Text('无法登录').fontSize(14).fontColor('#666') } .margin({ top: 15 }) Blank() //弹簧组件 //其他登录方式 Column() { Text('其他登录方式').fontSize(14).height(22).fontColor('#666').margin({ bottom: 28 }) Row() { Image($r('app.media.Image3')).width(34) Image($r('app.media.Image8')).width(34).fillColor('#56a44a') Image($r('app.media.Image1')).width(34).fillColor('#c8493b') Image($r('app.media.Image6')).width(34).fillColor('#4ba0e8') } .margin({ bottom: 30 }) .justifyContent(FlexAlign.SpaceAround) .width('100%') } .width('100%') } .width('100%') .height('100%') .backgroundImage($r('app.media.Image4')) .backgroundImageSize(ImageSize.Cover) .padding(20) } .height('100%') .width('100%') } } ``` #### 弹性布局Flex ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Flex({ //主轴方向 direction: FlexDirection.Row, //主轴方向-于左上角水平向右排布-默认值 // direction: FlexDirection.Column, //主轴方向-于左上角垂直向下排布 // direction: FlexDirection.RowReverse, //主轴方向-于右上角水平向左排布 // direction: FlexDirection.ColumnReverse, //主轴方向-于左下角垂直向上排布 //主轴对齐方式 justifyContent: FlexAlign.Start, //主轴对齐方式-在主轴上靠起起始端排布-默认值 // justifyContent: FlexAlign.Center, //主轴对齐方式-在主轴上居中排布 // justifyContent: FlexAlign.End, //主轴对齐方式-在主轴上靠尾端排布 // justifyContent: FlexAlign.SpaceBetween, //主轴对齐方式-在主轴上两端对齐排布 // justifyContent: FlexAlign.SpaceAround, //主轴对齐方式-在主轴上每个组件的主轴方向外边距相等排布 // justifyContent: FlexAlign.SpaceEvenly, //主轴对齐方式-在主轴上每个组件的主轴方向均分分布排布 //交叉轴对齐方式 alignItems: ItemAlign.Start,// // alignItems: ItemAlign.Auto, // alignItems: ItemAlign.Center,//在交叉轴上居中排布 // alignItems: ItemAlign.End,//在交叉轴上靠尾部排布 // alignItems: ItemAlign.Baseline,//在交叉轴上靠尾部排布 // alignItems: ItemAlign.Stretch,//在交叉轴上拉伸铺满排布 //换行wrap wrap: FlexWrap.NoWrap,//单行压缩-默认值 // wrap: FlexWrap.Wrap,//换行不压缩 // wrap: FlexWrap.WrapReverse,//排布方式反转,换行不压缩 }) { Text('组件1').border({ width: 1 }).padding(10).backgroundColor(Color.Green) Text('组件2').border({ width: 1 }).padding(10).backgroundColor(Color.Green) Text('组件3').border({ width: 1 }).padding(10).backgroundColor(Color.Green) Text('组件4').border({ width: 1 }).padding(10).backgroundColor(Color.Green) Text('组件5').border({ width: 1 }).padding(10).backgroundColor(Color.Green) Text('组件6').border({ width: 1 }).padding(10).backgroundColor(Color.Green) Text('组件7').border({ width: 1 }).padding(10).backgroundColor(Color.Green) Text('组件8').border({ width: 1 }).padding(10).backgroundColor(Color.Green) } .backgroundColor(Color.Gray) .height('100%').width('100%') } .height('100%').width('100%') } } ``` #### 绝对定位position&层级zIndex ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { //父组件 Text('子组件1').backgroundColor(Color.Green).padding(10) //默认位置 Text('子组件2').backgroundColor(Color.Pink).padding(10) .position({ x: 150, y: 0 }) //将此组件移动至(x: 0, y: 0)位置,原有位置由其他组件使用,可层叠 .zIndex(0)//图层 数字越大,层级越高 Text('子组件3').backgroundColor(Color.Yellow).padding(10) } .width(300).height(300).backgroundColor('#ccc') } } } ``` #### 综合案例-人气卡片 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Column() { Text('VIP').width(40).height(20) .position({ x: 0, y: 0}) .zIndex(1) .borderRadius({ topLeft: 10, bottomRight: 10 }) .border({ width: 2, color: '#fbe7a3' }) .backgroundColor('#e49642') .fontColor('#fbe7a3') .fontStyle(FontStyle.Italic) .fontWeight(700) .textAlign(TextAlign.Center) Image($r('app.media.Image2')).width('100%').borderRadius(10) Row() { Image($r('app.media.Image1')).width(20).fillColor(Color.White) .padding(3) .backgroundColor('#55b7f4') .borderRadius(10) .margin({ left: 6, right: 6 }) Text('飞狗MOCO').fontWeight(700) } .width('100%').height(30) } .width(160).height(210) .backgroundColor(Color.White) } .backgroundColor(Color.Pink) .width('100%').height('100%') } } } ``` #### 层叠布局 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Stack({ // alignContent: Alignment.TopStart,//在顶端靠起始部位堆叠 // alignContent: Alignment.Top,//在顶端靠居中堆叠 // alignContent: Alignment.TopEnd,//在顶端靠结尾部位堆叠 // alignContent: Alignment.Start,//在中部靠起始部位堆叠 // alignContent: Alignment.Center,//在中部靠中间堆叠-默认值 // alignContent: Alignment.End,//在中部靠结尾部位堆叠 // alignContent: Alignment.BottomStart,//在底端靠起始部位堆叠 // alignContent: Alignment.Bottom,//在底端靠居中堆叠 // alignContent: Alignment.BottomEnd,//在底端靠结尾部位堆叠 }) { Text('组件1').width('80%').height('80%').backgroundColor(Color.Gray) .zIndex(1) Text('组件2').width('40%').height('40%').backgroundColor(Color.Yellow) .zIndex(2) Text('组件3').width('20%').height('20%').backgroundColor(Color.Green) .zIndex(3)//可使用zindex控制层级 } .width('100%').height('100%') .backgroundColor(Color.Pink) } } } ``` #### 综合案例-B站视频卡片 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Column() { Stack({ alignContent: Alignment.Bottom }) { Image($r('app.media.Image2')).width('100%') Row() { Row() { Image($r('app.media.Image1')).width(12).fillColor(Color.White).margin({ right: 5 }) Text('288万').fontSize(12).fontColor(Color.White).margin({ right: 10 }) Image($r('app.media.Image4')).width(12).fillColor(Color.White).margin({ right: 5 }) Text('8655').fontColor(Color.White).fontSize(12) } Text('4:33').fontColor(Color.White).fontSize(12).margin({ right: 5 }) } .justifyContent(FlexAlign.SpaceBetween).width('100%') }.width(200).height(125) Column() { Text('【凤凰传奇新歌】欢迎来到国风统治区:唢呐一响神曲《铁衣...').fontSize(14).lineHeight(16) Row() { Text('19万点赞').padding(5).fontColor(Color.Orange).backgroundColor(Color.Pink).fontSize(12) Image($r('app.media.Image3')).width(15).fillColor('#ccc') } .width('100%') .justifyContent(FlexAlign.SpaceBetween) .margin(10) } .margin({ top: 5 }).width('100%') .justifyContent(FlexAlign.SpaceBetween) } .width(200).height(200) } } } ``` #### 支付宝首页 ```TypeScript @Entry @Component struct Index { @State message: string = 'Hello World'; build() { RelativeContainer() { Stack({ alignContent: Alignment.BottomStart }) { //主页面 Stack({ alignContent: Alignment.Top }) { //顶部导航 Row() { Column() { Text('北京').fontSize(18).fontColor('#fff') Text('晴 2℃').fontSize(12).fontColor('#fff') Image($r('app.media.zfb_head_down')).width(12).fillColor('#fff') .position({ x: 40, y: 0 }) } Row() { Image($r('app.media.zfb_head_search')).width(20).fillColor('#666').margin({ left: 5, right: 5 }) Text('北京交通一卡通').layoutWeight(1) Text('搜索') .width(55) .fontColor('#5b73d') .fontWeight(700) .textAlign(TextAlign.Center) .border({ width: { left: 1 }, color: '#ccc' }) } .height(32) .layoutWeight(1) .backgroundColor('#fff') .borderRadius(5) .margin({ left: 25, right: 12 }) Image($r('app.media.zfb_head_plus')).width(30).fillColor('#fff') } .width('100%') .height(60) .backgroundColor('#5b73de') .zIndex(2) .padding({ left: 10, right: 10 }) //主页面 Scroll() { Column() { //快捷按钮 Row() { Column() { Image($r('app.media.zfb_top_scan')).width(36).fillColor('#fff') Text('扫一扫').fontColor('#fff') } .layoutWeight(1) Column() { Image($r('app.media.zfb_top_pay')).width(36).fillColor('#fff') Text('收付款').fontColor('#fff') } .layoutWeight(1) Column() { Image($r('app.media.zfb_top_travel')).width(36).fillColor('#fff') Text('出行').fontColor('#fff') } .layoutWeight(1) Column() { Image($r('app.media.zfb_top_card')).width(36).fillColor('#fff') Text('卡包').fontColor('#fff') } .layoutWeight(1) } .backgroundColor('#5b73de') .padding({ top: 5, bottom: 15 }) //导航区 Column({ space: 10 }) { Row() { Column() { Image($r('app.media.zfb_nav1')).width(28).margin({ bottom: 8 }) Text('滴滴出行').fontSize(12).fontColor('#666') } .layoutWeight(1) Column() { Image($r('app.media.zfb_nav2')).width(28).margin({ bottom: 8 }) Text('生活缴费').fontSize(12).fontColor('#666') } .layoutWeight(1) Column() { Image($r('app.media.zfb_nav3')).width(28).margin({ bottom: 8 }) Text('股票').fontSize(12).fontColor('#666') } .layoutWeight(1) Column() { Image($r('app.media.zfb_nav4')).width(28).margin({ bottom: 8 }) Text('蚂蚁森林').fontSize(12).fontColor('#666') } .layoutWeight(1) Column() { Image($r('app.media.zfb_nav5')).width(28).margin({ bottom: 8 }) Text('手机充值').fontSize(12).fontColor('#666') } .layoutWeight(1) } Row() { Column() { Image($r('app.media.zfb_nav6')).width(28).margin({ bottom: 8 }) Text('余额宝').fontSize(12).fontColor('#666') } .layoutWeight(1) Column() { Image($r('app.media.zfb_nav7')).width(28).margin({ bottom: 8 }) Text('花呗').fontSize(12).fontColor('#666') } .layoutWeight(1) Column() { Image($r('app.media.zfb_nav8')).width(28).margin({ bottom: 8 }) Text('飞猪旅行').fontSize(12).fontColor('#666') } .layoutWeight(1) Column() { Image($r('app.media.zfb_nav9')).width(28).margin({ bottom: 8 }) Text('淘票票').fontSize(12).fontColor('#666') } .layoutWeight(1) Column() { Image($r('app.media.zfb_nav10')).width(28).margin({ bottom: 8 }) Text('饿了么').fontSize(12).fontColor('#666') } .layoutWeight(1) } Row() { Column() { Image($r('app.media.zfb_nav11')).width(28).margin({ bottom: 8 }) Text('读书听书').fontSize(12).fontColor('#666') } .layoutWeight(1) Column() { Image($r('app.media.zfb_nav12')).width(28).margin({ bottom: 8 }) Text('基金').fontSize(12).fontColor('#666') } .layoutWeight(1) Column() { Image($r('app.media.zfb_nav13')).width(28).margin({ bottom: 8 }) Text('直播广场').fontSize(12).fontColor('#666') } .layoutWeight(1) Column() { Image($r('app.media.zfb_nav14')).width(28).margin({ bottom: 8 }) Text('医疗健康').fontSize(12).fontColor('#666') } .layoutWeight(1) Column() { Image($r('app.media.zfb_nav15_more')).width(28).margin({ bottom: 8 }) Text('更多').fontSize(12).fontColor('#666') } .layoutWeight(1) } } .width('100%') .backgroundColor('#fff') .borderRadius({ topLeft: 20, topRight: 20 }) .padding(10) //产品区 Row({ space: 5 }) { Image($r('app.media.zfb_pro_pic1')).layoutWeight(1) Image($r('app.media.zfb_pro_pic2')).layoutWeight(1) Image($r('app.media.zfb_pro_pic3')).layoutWeight(1) } .padding(10) Column({ space: 10 }) { Image($r('app.media.zfb_pro_list1')).width('100%') Image($r('app.media.zfb_pro_list2')).width('100%') } .padding(10) } .width('100%') .padding({ top: 60, bottom: 60 }) } } .width('100%').height('100%').zIndex(1) //底部导航 Row() { //Home Column() { Image($r('app.media.zfb_tab_home')).width(35) } .layoutWeight(1) //money management Column() { Image($r('app.media.zfb_tab_money')).width(28) Text('理财').fontSize(12).margin({ bottom: 2 }) } .layoutWeight(1) //life Column() { Image($r('app.media.zfb_tab_life')).width(28) Text('生活').fontSize(12).margin({ bottom: 2 }) } .layoutWeight(1) //massage Column() { Image($r('app.media.zfb_tab_chat')).width(28) Text('消息').fontSize(12).margin({ bottom: 2 }) } .layoutWeight(1) //me Column() { Image($r('app.media.zfb_tab_me')).width(28) Text('我的').fontSize(12).margin({ bottom: 2 }) } .layoutWeight(1) } .width('100%').height(60).backgroundColor(Color.White).zIndex(2) } .width('100%').height('100%').backgroundColor('#fff') } } } ``` ## 构建应用 #### 字符串拼接和模板字符串 ```TypeScript //字符串拼接 let name = '吕布'; let age = 18; console.log('简介信息:', '姓名:' + name);//当'+'的操作数之一为string类型,则起到字符串拼接功能 console.log('简介信息:', '年龄:' + age); //模板字符串 let name1: string = `小明`;//声明一个模板字符串 let age1 = 18; console.log('简介', `姓名:${name1},年龄:${age1}岁`); ``` #### 类型转换(数字和字符串) ```TypeScript //类型转换(数字和字符串) // 1.字符串转数字 let str1: string = '1'; let str2: string = '1.1'; let str3: string = '1.1a'; let str4: string = 'a'; //Number() 直接转数字-失败返回`NaN` console.log('str1 = ', Number(str1));//1 console.log('str2 = ', Number(str2));//1.1 console.log('str3 = ', Number(str3));//NaN console.log('str4 = ', Number(str4));//NaN console.log('---------------------------------'); //parseInt 仅保留整数部分-失败返回`NaN` console.log('str1 = ', parseInt(str1));//1 console.log('str2 = ', parseInt(str2));//1 console.log('str3 = ', parseInt(str3));//1 console.log('str4 = ', parseInt(str4));//NaN console.log('---------------------------------'); //parseFloat 保留小数部分-失败返回`NaN` console.log('str1 = ', parseFloat(str1));//1 console.log('str2 = ', parseFloat(str2));//1.1 console.log('str3 = ', parseFloat(str3));//1.1 console.log('str4 = ', parseFloat(str4));//NaN // 2.数字转字符串 let num1: number = 1.1; let num2: number = 1.123; let num3: number = 1.55555; //toString() console.log('num1 =',num1.toString());//1.1 console.log('num2 =',num2.toString());//1.123 console.log('num3 =',num3.toString());//1.55555 console.log('---------------------------------'); //toFixed(保留小数位数) 四舍五入 范围在2~36之间 console.log('num1 =', num1.toFixed(2));//1.10 console.log('num2 =', num2.toFixed());//1 取整 console.log('num3 =', num3.toFixed(3));//1.556 ``` #### 点击事件 ```TypeScript //点击事件 @Entry @Component struct Index { @State message: string = 'Hello World'; build() { Column() { Button('按钮组件') .onClick(() => { //点击事件 AlertDialog.show({ //弹出对话框 message: '点击了按钮组件' }) }) Text('文本组件') .onClick(() => { AlertDialog.show({ message: '点击了文本组件' }) }) } .width('100%').height('100%') } } ``` #### 状态管理 ```TypeScript //状态管理 let myName: string = '张三'; //全局变量 @Entry @Component struct Index { myAge: number = 18; //在组件内声明普通变量不需要let关键字 @State myMessage: string = 'Hello World'; //在组件内声明状态变量 build() { Column() { //可在Index内找到并直接使用全局变量 Text(myName).onClick(() => { myName = '李四' //点击时,普通变量myName已修改,但不会显示修改后内容 }); //在组件内声明的普通变量,需要使用this关键字找到 Text(this.myMessage).onClick(() => { this.myMessage = '你好 世界' //点击时,状态变量myMessage将UI中的内容同步修改 }) .padding(10) .backgroundColor(Color.Yellow) .borderRadius(5) } .width('100%') } } ``` #### 计数器案例 ```TypeScript //计数器案例 @Entry @Component struct Index { @State count: number = 0; build() { Row() { Button('-').onClick(() => { if (this.count <= 0) { } else { this.count--; } }) Text(this.count.toString()).margin(10) Button('+').onClick(() => { if (this.count >= 10) { } else { this.count++; } }) } .padding(20) } } ``` #### 算数运算符和赋值运算符 ```TypeScript console.log('9 + 2 =', 9 + 2); console.log('9 - 2 =', 9 - 2); console.log('9 * 2 =', 9 * 2); console.log('9 / 2 =', 9 / 2); console.log('9 % 2 =', 9 % 2); let num1: number = 10; let num2: number = 10; let num3: number = 10; let num4: number = 10; let num5: number = 10; console.log('num = 10'); console.log('num += 2 => num =',num1 += 2); console.log('num -= 2 => num =',num2 -= 2); console.log('num *= 2 => num =',num3 *= 2); console.log('num /= 2 => num =',num4 /= 2); console.log('num %= 2 => num =',num5 %= 2); ``` #### 点赞案例 ```TypeScript //点赞案例 @Entry @Component struct Index { @State likesState: string = '#666'; @State likesNumber: number = 0; build() { Column() { Column({ space: 8 }) { Image($r('app.media.Image1')).width('100%').borderRadius({ topLeft: 6, topRight: 6 }) Text('考眼力又来了你能看到几只鸭子?').fontSize(35).padding({ left: 5, right: 5 }) }.width('100%') Row({ space: 8 }) { Row({ space: 5 }) { Image($r('app.media.Image3')).width(50) Text('视野联行眼镜') } Row({ space: 5 }) { Image($r('app.media.Image2')).width(20).fillColor(this.likesState) Text(this.likesNumber.toString()).fontSize(20).fontColor(this.likesState) }.margin(10) .onClick(() => { if (this.likesState == '#666') { this.likesNumber += 1; this.likesState = '#ff0000'; } }) }.width('100%').margin(10).justifyContent(FlexAlign.SpaceBetween).padding({ left: 5, right: 5 }) }.width('100%') } } ``` #### 一元、比较、逻辑运算符 ```TypeScript //一元、比较、逻辑运算符 // 1.前置`++`、前置`--` let num1: number = 10; let num2: number = ++num1; console.log(`num1 = ${num1}, num2 = ++num1 => num2 = ${num2}, num1 = ${num1}`); //num2 = 11,num1 = 11 let num3: number = 10; let num4: number = --num3; console.log(`num3 = ${num3}, num4 = --num3 => num4 = ${num4}, num3 = ${num3}`); //num4 = 9, num3 = 9 // 2.后置`++`、后置``--` let num5: number = 10; let num6: number = num5++; console.log(`num5 = ${num5}, num6 = num5++ => num6 = ${num6}, num5 = ${num5}`); //num6 = 10, num5 = 11 let num7: number = 10; let num8: number = num7-- console.log(`num7 = ${num7}, num8 = num7-- => num8 = ${num8}, num7 = ${num7}`); //num8 = 10, num7 = 9 ``` #### 运算符优先级 和其他语言一样 #### 综合案例-美团购物车 ```TypeScript //综合案例-美团购物车 @Entry @Component struct Index { @State count: number = 1; @State oldPrice: number = 40.4; @State newPrice: number = 10.4; build() { Column() { Column() { Row({ space: 10 }) { Image($r('app.media.product1')).width(100).borderRadius(8) Column({ space: 10 }) { Column({ space: 6 }) { Text('冲销量1000ml缤纷八果水果捞').lineHeight(20).fontSize(14) Text('含1份折扣商品').fontSize(12).fontColor('#7f7f7f') }.width('100%').alignItems(HorizontalAlign.Start) Row() { Row({ space: 5 }) { Text() { Span('¥').fontSize(14) Span(this.newPrice.toFixed(2)).fontSize(18) }.fontColor('#ff4000') Text() { Span('¥') Span(this.oldPrice.toFixed(2)) }.fontSize(14).fontColor('#999').decoration({ type: TextDecorationType.LineThrough, color: '#999' }) } Row() { Text('-') .width(22) .height(22) .border({ width: 1, color: '#e1e1e1', radius: { topLeft: 5, bottomLeft: 5 } }) .textAlign(TextAlign.Center) .fontWeight(700) .onClick(() => { if (this.count > 1) { this.count--; } }) Text(this.count.toString()) .height(22) .border({ width: { top: 1, bottom: 1 }, color: '#e1e1e1' }) .padding({ left: 10, right: 10 }) .fontSize(14) Text('+') .width(22) .height(22) .border({ width: 1, color: '#e1e1e1', radius: { topRight: 5, bottomRight: 5 } }) .textAlign(TextAlign.Center) .fontWeight(700) .onClick(() => { this.count++; }) } }.width('100%').justifyContent(FlexAlign.SpaceBetween) }.height(75).layoutWeight(1).justifyContent(FlexAlign.SpaceBetween) }.width('100%').alignItems(VerticalAlign.Top).padding(20) Row({ space: 10 }) { Column({ space: 5 }) { Text() { Span(`已选 ${this.count} 件,`).fontColor('#848484') Span('合计:') Span('¥').fontColor('#fd4104') Span((this.count * this.newPrice).toFixed(2)).fontColor('#fd4104').fontSize(16) }.fontSize(14) Text(`共减¥${((this.count * this.oldPrice) - (this.count * this.newPrice)).toFixed(2)}`) .fontColor('#fd4104') .fontSize(12) }.alignItems(HorizontalAlign.End) // 结算按钮 Button('结算外卖') .width(110) .height(40) .backgroundColor('#fed70e') .fontColor('#564200') .fontSize(16) .fontWeight(600) } .width('100%') .height(70) .backgroundColor('#fff') .position({ x: 0, y: '100%' }) .translate({ y: '-100%' }) .padding({ left: 20, right: 20 }) .justifyContent(FlexAlign.End) } }.width('100%').height('100%').backgroundColor('#f3f3f3') } } ``` #### 数组操作-增删改查 ```TypeScript //数组操作-增删改查 let names: string[] = ['Name1', 'Name2', 'Name3', 'Name4', 'Name5']; //1.添加 //在开头新增 array.unshift(元素值); => 返回array.length names.unshift('Name0'); console.log(`names[0] = ${names[0]}`); //在结尾新增 array.push(元素值); => 返回array.length names.push('Name6') console.log(`names[names.length - 1] = ${names[names.length - 1]}`); //2.删除 //删除数组第一个元素 array.shift(); => 返回被删除的元素值 console.log(`删除${names.shift()}元素`); console.log(`删除${names.shift()}元素`); names[0] = 'Name0'; names[1] = 'Name1'; names[2] = 'Name2'; names[3] = 'Name3'; names[4] = 'Name4'; names[5] = 'Name5'; names[6] = 'Name6'; //删除数组最后一个元素 array.pop(); => 返回被删除的元素值 console.log(`删除${names.pop()}元素`); console.log(`删除${names.pop()}元素`); names[0] = 'Name0'; names[1] = 'Name1'; names[2] = 'Name2'; names[3] = 'Name3'; names[4] = 'Name4'; names[5] = 'Name5'; names[6] = 'Name6'; //3.修改 console.log(`names[1] = ${names[1]} => names[1] = '名字2' => names[1] = ${names[1] = '名字2'}`); names[1] = 'Name2' //4.查找 console.log(`names[0] = ${names[0]}`); //5.长度 console.log(`names.length = ${names.length}`); names[0] = 'Name0'; names[1] = 'Name1'; names[2] = 'Name2'; names[3] = 'Name3'; names[4] = 'Name4'; names[5] = 'Name5'; names[6] = 'Name6'; //array.splice(起始修改元素下标, 需修改元素数量, 删除后在该位置新增的元素1, 删除后在该位置新增的元素2, ..., 删除后在该位置新增的元素n) names.splice(0, names.length, '姓名0', '姓名1', '姓名2', '姓名3', '姓名4',) console.log('names[0] = ', names[0]); console.log('names[1] = ', names[1]); console.log('names[2] = ', names[2]); console.log('names[3] = ', names[3]); console.log('names[4] = ', names[4]); console.log(`names.length = ${names.length}`); ``` #### 语句-if、switch语句、三元运算符 ```TypeScript let score: number = 77; if (score >= 80) { console.log('优秀'); } else if (score >= 70) { console.log('良好'); } else if (score >= 60) { console.log('及格'); } else { console.log('不及格'); } let fruitsName: string = '苹果'; switch (fruitsName) { case '苹果': console.log(`苹果价格:2.80元/斤`); break; case '香蕉': console.log(`香蕉价格:5.80元/斤`); break; case '西瓜': console.log(`西瓜价格:1.80元/斤`); break; default: console.log(`请输入正确的水果名称`); } console.log(` 1 >= 2 ? '是的' : '不是' => ${1 >= 2 ? '是的' : '不是' }`); ``` #### 条件渲染 ```TypeScript //条件渲染 @Entry @Component struct Index { @State age: number = 16; build() { Column() { if (this.age < 18) { Text('未成年') } else if (this.age <= 60) { Text('成年人') } else { Text('老年人') } Button('+5岁').onClick(() => { this.age += 5; }) Text(`当前年龄:${this.age}`); } } } ``` #### 京东加购案例 ```TypeScript //京东加购案例 @Entry @Component struct Index { @State count: number = 0; //库存 build() { Column() { Column() { // 底部菜单 Row({ space: 10 }) { // 左侧菜单 Row() { Column({ space: 5 }) { Image($r('app.media.ic_dianpu')).width(20) Text('店铺').fontSize(10).fontColor('#262626') } Column({ space: 5 }) { Image($r('app.media.ic_kefu')).width(20).fillColor('#666') Text('客服').fontSize(10).fontColor('#262626') } Column({ space: 5 }) { Image($r('app.media.ic_cart2')).width(20).fillColor('#666') Text('购物车').fontSize(10).fontColor('#262626') } }.layoutWeight(1).justifyContent(FlexAlign.SpaceBetween) if (this.count >= 1) { // 右侧按钮 -- 可以购买 Row({ space: 5 }) { Button('加入购物车') .width(105) .height(40) .backgroundColor('#ffcc00') .fontSize(14) .fontWeight(600) Button('立即购买') .width(105) .height(40) .backgroundColor('#f92c1b') .fontSize(14) .fontWeight(600) } } else { // 右侧按钮 -- 不能购买 Row() { Button('查看类似商品') .width(170) .height(40) .backgroundColor('#ffcc00') .fontSize(14) .fontWeight(600) } // 消息提示:库存 <= 0 显示,否则隐藏 Row() { // 左侧 Row({ space: 5 }) { Image($r('app.media.ic_lingdang')).width(12).fillColor('#de6a1c') Text('该商品暂时没有库存,看看相似商品吧').fontSize(10).fontColor('#de6a1c') } // 右侧 Image($r('app.media.ic_shangjiantou')) .width(15) .padding(3) .fillColor('#d0662c') .backgroundColor('rgba(0,0,0,0.1)') .borderRadius(8) } .width('100%') .height(36) .backgroundColor('#fbf9da') .position({ x: 0, y: '-36' }) .padding({ left: 20, right: 20 }) .justifyContent(FlexAlign.SpaceBetween) } } .width('100%') .height(60) .backgroundColor('#f7f7f7') .padding({ left: 20, right: 10 }) } .position({ x: 0, y: '100%' }) .translate({ y: '-100%' }) } .width('100%') .height('100%') .padding({ bottom: 20 }) .backgroundColor('#f2f2f2') } } ``` #### 循环语句 ```TypeScript //循环语句 //while let i: number = 0; while (i < 5) { console.log(`while循环的第${i + 1}次`); i++; } i = 0; //do while do { console.log(`do while循环的第${i + 1}次`); i++; } while (i < 5); // for for (let nn: number = 0; nn < 5; nn++) { console.log(`for循环的第${nn + 1}次`); } ``` #### 退出循环`break`、`continue` ```TypeScript //break 终止整个循环 for (let i = 1; i <= 10; i++) { if (i == 5) { console.log(`第${i}次循环,break退出`); break; } console.log(`第${i}次循环`); } console.log(`循环结束`); //continue 退出当前一次循环的执行,继续执行下一次循环 for (let i = 1; i <= 10; i++) { if (i == 2) { console.log(`第${i}次循环,continue退出当次循环`); continue; console.log(`此语句不执行`); } console.log(`第${i}次循环`); } console.log(`循环结束`); ``` #### 遍历数组`for`、`for of` ```TypeScript //遍历数组for、for of let names: string[] = ['Name0', 'Name1', 'Name2', 'Name3', 'Name4']; //for for (let i: number = 0; i < names.length; i++) { console.log(`names[${i}] = ${names[i]}`); } //for of for (let item of names) { console.log(` ${item} `); } //需求1 let demand1: number[] = [22, 3, 44, 55, 80]; let sumDemand1 = 0; for (let item of demand1) { sumDemand1 += item; } console.log(`数组demand1的累加和 = ${sumDemand1}`); //需求2 let demand2: number[] = [22, 3, 44, 55, 80, 10, 11, 5, -1]; let demand2NewArray: number[] = []; for (let i of demand2) { if (i >= 10) { demand2NewArray.push(i); } } console.log(`需求2新数组`); for (let item of demand2NewArray) { console.log(` ${item} `); } //需求3 let demand3: number[] = [22, 3, 0, 55, 0, 0, 11, 5, 0]; let demand3NewArray: number[] = []; for (let i of demand3) { if (i != 0) { demand3NewArray.push(i); } } console.log(`需求3新数组`); for (let item of demand3NewArray) { console.log(` ${item} `); } ``` #### 对象数组 ```TypeScript //对象数组 interface Person { studentID: number name: string gender: 'Man' | 'Women' age: number }; let studentArr: Person[] = [ { studentID: 1, name: '张三', gender: 'Man', age: 10 }, { studentID: 2, name: '李四', gender: 'Women', age: 11 }, { studentID: 3, name: '王五', gender: 'Man', age: 10 }, { studentID: 4, name: '赵六', gender: 'Women', age: 9 } ]; //使用JSON.stringifly(复杂类型)使对象/数组转成字符串的格式输出 console.log('数组:', JSON.stringify(studentArr)); console.log(`ID: ${studentArr[0].studentID} 姓名:${studentArr[0].name}`); for(let num of studentArr) { console.log(`${num.name}`); } ``` #### ForEach-渲染控制 ```TypeScript //ForEach-渲染控制 @Entry @Component struct Index { @State titles: string[] = ['电子产品', '精品服饰', '母婴产品', '影音娱乐', '海外旅游']; build() { Column() { ForEach(this.titles, (item: string, index: number) => { Text(`${item}`) .fontSize(24) .fontWeight(700) .fontColor(Color.Orange) .padding(15) .width('100%') }) } } } ``` #### ForEach-渲染控制-案例 ```TypeScript //ForEach-渲染控制 - 案例 interface Journalism { title: string createTime: string }; @Entry @Component struct Index { @State playbar: Journalism[] = [ { title: '近200+自动驾驶数据集全面调研!一览如何数据闭环全流程', createTime: '2024-01-31 09:59:43' }, { title: 'MySQL Shell 8.0.32 for GreatSQL编译二进制包', createTime: '2024-01-31 09:55:53' }, { title: '在Redis中如何实现分布式事务的一致性?', createTime: '2024-01-31 09:54:51' } ] build() { Scroll() { Column() { ForEach(this.playbar, (arr: Journalism, index: number) => { Column() { Text(`${arr.title}`).width('100%').fontSize(15).fontColor('#303030').lineHeight(20) Text(`${arr.createTime}`).width('100%').fontSize(12).fontColor('rgb(192, 192, 192)').margin({ top: 15 }) } .padding({ top: 15, bottom: 15 }) .width('100%') .border({ width: { bottom: 2 }, color: '#f4f4f4' }) }) } } } } ``` #### 案例-生肖抽奖卡 ```TypeScript //案例-生肖抽奖卡 interface ImageDataCustom { url: string count: number } @Entry @Component struct Index { //卡片数组 @State images: ImageDataCustom[] = [ { 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 prize: string[] = ['xm', 'hw', 'pg']; @State prizeIndex: number = 0; //奖品下标 @State popupTransparency: number = 0; //弹页透明度 @State originalPageLevel: number = 1; //原始页面层级 @State popupPageLevel: number = 0; //弹页面层级 @State prizePageLevel: number = 0; //大奖页面层级 @State popupZoomTime_x: number = 0; //弹窗缩放时间x @State popupZoomTime_y: number = 0; //弹窗缩放时间y @State randomSequenceNumber: number = -1; //随机弹窗数字 @State randomPhone: number = -1; //随机手机 @State isMeetTheGrandPrizeCondition: boolean = false; //满足大奖条件 build() { Stack() { //原始页面 Column() { Grid() { ForEach(this.images, (arr: ImageDataCustom, index: number) => { GridItem() { //角标组件 Badge({ count: arr.count, //角标数值 position: BadgePosition.RightTop, //角标位置 style: { badgeSize: 16, fontSize: 16, badgeColor: '#fa2a2d' } //角标风格 }) { Image($r(arr.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.popupTransparency = 100; this.originalPageLevel = -1; this.popupPageLevel = 10; this.popupZoomTime_y = 1; this.popupZoomTime_x = 1; this.randomSequenceNumber = (Math.floor(Math.random() * 6)) //取[0,1)之间的小数 * 6 再向下取整 }) }.width('100%').height('100%').zIndex(this.originalPageLevel) if (this.isMeetTheGrandPrizeCondition) { //大奖层 Column({ space: 30 }) { Text('恭喜获得手机一部').fontColor('#f5ebcf').fontSize(25).fontWeight(700) Image($r(`app.media.${this.prize[this.prizeIndex]}`)).width(300) Button('再来一次') .width(200) .height(50) .backgroundColor(Color.Transparent) .border({ width: 2, color: '#fff9e0' }) .onClick(() => { this.isMeetTheGrandPrizeCondition = false; 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 } ]; }) } .width('100%') .height('100%') .backgroundColor('#cc000000') .zIndex(this.prizePageLevel) .justifyContent(FlexAlign.Center) } else { //弹层 Column({ space: 30 }) { Text('获得生肖卡').fontColor('#f5ebcf').fontSize(25).fontWeight(FontWeight.Bold) Image($r(`app.media.img_0${this.randomSequenceNumber}`)).width(200) .scale({ x: this.popupZoomTime_x, y: this.popupZoomTime_y }) .animation({ duration: 500 }) Button('开心收下') .width(200) .height(50) .backgroundColor(Color.Transparent) .border({ width: 2, color: '#fff9e0' }) .onClick(() => { this.popupTransparency = 0; this.popupZoomTime_y = 0; this.popupZoomTime_x = 0; this.originalPageLevel = 10; this.popupPageLevel = -1; //收下后的界面变化 需要修改整个对象 this.images[this.randomSequenceNumber] = { url: `app.media.img_0${this.randomSequenceNumber}`, count: this.images[this.randomSequenceNumber].count + 1 }; // 错误示例 // this.images[this.randomSequenceNumber].url = `app.media.img_0${this.randomSequenceNumber}`; // this.images[this.randomSequenceNumber].count++; //检索是否集齐 this.isMeetTheGrandPrizeCondition = true; for (let arr of this.images) { if (arr.count == 0) { this.isMeetTheGrandPrizeCondition = false; break; } else { //中大奖 this.prizePageLevel = 1; this.originalPageLevel = 0; this.prizeIndex = Math.floor(Math.random() * 4); } } }) } .width('100%') .height('100%') .backgroundColor('#cc000000') .justifyContent(FlexAlign.Center) .zIndex(this.popupPageLevel) .opacity(this.popupTransparency) //设置透明度 .animation({ duration: 500 }) //设置动画时长 } } } } ``` ## 组件化开发 #### Swiper轮播组件 ```TypeScript //Swiper轮播组件 //Doc URL:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-swiper-V5 @Entry @Component struct Index { build() { Column() { Swiper() { Text('组件1').backgroundColor(Color.Gray) Text('组件2').backgroundColor(Color.Orange) Text('组件2').backgroundColor(Color.Red) }.width('100%').height(100) //不在子元素设置宽高,仅在Swiper轮播组件中设置 Swiper() { Image($r('app.media.ic_swiper_xmyp01')) Image($r('app.media.ic_swiper_xmyp02')) Image($r('app.media.ic_swiper_xmyp03')) Image($r('app.media.ic_swiper_xmyp04')) } .width('100%') .loop(true) //是否开启循环-默认值 .autoPlay(true) //是否开启自动播放 .interval(3000) //自动播放时间间隔-默认值(ms) .vertical(false) //是否纵向轮播-默认值 .indicator( //轮播指向点样式 Indicator.dot() .itemWidth(20)//未选中指向点-宽 .itemHeight(20)//未选中指向点-高 .color(Color.Black)//未选中指向点-颜色 .selectedItemWidth(25)//选中指向点-宽 .selectedItemHeight(25)//选中指向点-高 .selectedColor(Color.White) //选中指向点-颜色 ) } } } ``` #### 案例 ```TypeScript //Swiper 案例 @Entry @Component struct Index { build() { Swiper() { Image($r('app.media.ic_swiper_xmyp01')) Image($r('app.media.ic_swiper_xmyp02')) Image($r('app.media.ic_swiper_xmyp03')) Image($r('app.media.ic_swiper_xmyp04')) } .width('100%') .autoPlay(true) .interval(4000) .indicator( Indicator.dot() .itemWidth(10) .selectedItemWidth(30) .selectedColor(Color.White) ) .aspectRatio(750/313)//设置宽高比 } } ``` #### 样式&结构重用 ```TypeScript //样式&结构重用 /* @Extend扩展组件Doc URL:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-extend-V5 @Styles定义组件重用样式Doc URL:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-style-V5 @Builder自定义构建函数Doc URL:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-builder-V5 */ //仅可全局定义,可以传参 @Extend(Text) function fancy(bgColor: ResourceColor, msg: string) { .textAlign(TextAlign.Center) .backgroundColor(bgColor) .fontColor(Color.White) .fontSize(30) .fontWeight(FontWeight.Bold) .onClick(() => { AlertDialog.show({ message: msg }) }) } //可局部、全局定义,仅局部定义时可传参 @Styles function publicAttribute() { .width('100%') .height(50) .onClick(() => { AlertDialog.show({ message: '点击' }) }) } //可局部、全局定义,仅局部定义时可传参 @Builder function newItem() { Row({ space: 10 }) { Column({ space: 10 }) { Image($r('app.media.ic_reuse_01')).width(60) Text('阿里拍卖') } Column({ space: 10 }) { Image($r('app.media.ic_reuse_02')).width(60) Text('菜鸟快递') } Column({ space: 10 }) { Image($r('app.media.ic_reuse_03')).width(60) Text('芭芭农场') } Column({ space: 10 }) { Image($r('app.media.ic_reuse_04')).width(60) Text('阿里药房') } }.width('100%').justifyContent(FlexAlign.SpaceBetween) } @Entry @Component struct Index { build() { Column({ space: 30 }) { Swiper() { Text('组件1').fancy(Color.Orange, '组件1弹窗') Text('组件2').fancy(Color.Green, '组件2弹窗') Text('组件3').fancy(Color.Red, '组件3弹窗') Text('组件4').fancy(Color.Blue, '组件4弹窗') }.width('100%').height(300).autoPlay(true) Column() { Text('图片组件').publicAttribute() Button('按键组件').publicAttribute() } newItem() }.width('100%') } } ``` #### Scroll滚动容器 ```TypeScript //Scroll可滚动的容器组件Doc URL:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-scroll-V5 @Entry @Component struct Index { build() { Column() { Scroll() { Column({ space: 10 }) { ForEach(Array.from({ length: 5 }), (arr: string, index: number) => { Text('Text组件' + (index + 1)) .width('100%') .height(100) .textAlign(TextAlign.Center) .backgroundColor(Color.Orange) .fontSize(20) .fontColor(Color.White) .borderRadius(10) }) }.width('100%').padding(10) } .width('100%').height(400) .scrollable(ScrollDirection.Vertical) //滚动方向-默认值-垂直 } } } ``` #### Scroll属性 ```TypeScript //Scroll可滚动的容器组件Doc URL:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-scroll-V5 @Entry @Component struct Index { build() { Column() { Scroll() { Column({ space: 10 }) { ForEach(Array.from({ length: 5 }), (arr: string, index: number) => { Text('Text组件' + (index + 1)) .width('100%') .height(100) .textAlign(TextAlign.Center) .backgroundColor(Color.Orange) .fontSize(20) .fontColor(Color.White) .borderRadius(10) }) }.width('100%').padding(10) } .width('100%') .height(400) .scrollable(ScrollDirection.Vertical) //滚动方向-默认值-垂直 .scrollBar(BarState.Auto) //显示滚动条-默认值Auto滑动显示 .scrollBarColor(Color.Blue) //滚动条颜色 .scrollBarWidth(5) //滚动条宽度 .edgeEffect(EdgeEffect.Spring) //边缘滑动效果 默认值EdgeEffect.None } } } ``` #### Scroll控制器 ```TypeScript //Scroll可滚动的容器组件Doc URL:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-scroll-V5 @Entry @Component struct Index { myScroll: Scroller = new Scroller() build() { Column() { Scroll(this.myScroll) { Column({ space: 10 }) { ForEach(Array.from({ length: 5 }), (arr: string, index: number) => { Text('Text组件' + (index + 1)) .width('100%') .height(100) .textAlign(TextAlign.Center) .backgroundColor(Color.Orange) .fontSize(20) .fontColor(Color.White) .borderRadius(10) }) }.width('100%').padding(10) } .width('100%') .height(400) .scrollable(ScrollDirection.Vertical) //滚动方向-默认值-垂直 .scrollBar(BarState.Auto) //显示滚动条-默认值Auto滑动显示 .scrollBarColor(Color.Blue) //滚动条颜色 .scrollBarWidth(5) //滚动条宽度 .edgeEffect(EdgeEffect.Spring) //边缘滑动效果 默认值EdgeEffect.None Button('回到顶部').margin(10) .onClick(() => { this.myScroll.scrollEdge(Edge.Top) }) Button('获取移动距离').margin(10) .onClick(() => { const y = this.myScroll.currentOffset().yOffset AlertDialog.show({ message: `y: ${y}` }) }) } } } ``` #### Scroll事件 ```TypeScript //Scroll可滚动的容器组件Doc URL:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-scroll-V5 @Entry @Component struct Index { myScroll: Scroller = new Scroller() build() { Column() { Scroll(this.myScroll) { Column({ space: 10 }) { ForEach(Array.from({ length: 15 }), (arr: string, index: number) => { Text('Text组件' + (index + 1)) .width('100%') .height(100) .textAlign(TextAlign.Center) .backgroundColor(Color.Orange) .fontSize(20) .fontColor(Color.White) .borderRadius(10) }) }.width('100%').padding(10) } .width('100%') .height(400) .scrollable(ScrollDirection.Vertical) //滚动方向-默认值-垂直 .scrollBar(BarState.Auto) //显示滚动条-默认值Auto滑动显示 .scrollBarColor(Color.Blue) //滚动条颜色 .scrollBarWidth(5) //滚动条宽度 .edgeEffect(EdgeEffect.Spring) //边缘滑动效果 默认值EdgeEffect.None .onWillScroll((x, y) => { console.log('已滑动的距离:', this.myScroll.currentOffset().yOffset) }) Button('回到顶部').margin(10) .onClick(() => { this.myScroll.scrollEdge(Edge.Top) }) Button('获取移动距离').margin(10) .onClick(() => { const y = this.myScroll.currentOffset().yOffset AlertDialog.show({ message: `y: ${y}` }) }) } } } ``` #### Tabs容器组件 ```TypeScript //Tabs容器组件Doc URL:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-tabs-V5 @Entry @Component struct Index { @State selectIndex: number = 0; @Builder myBuilder(itemIndex: number, str: string) { Column() { Text(str).fontColor(itemIndex == this.selectIndex ? Color.Red : Color.Black) Image($r('app.media.background')) } } build() { Tabs({ barPosition: BarPosition.Start }) { //导航栏位置 - 默认值 TabContent() { Text('组件1内容').width('100%').textAlign(TextAlign.Center) }.tabBar(this.myBuilder(0, '组件1')) TabContent() { Text('组件2内容').width('100%').textAlign(TextAlign.Center) }.tabBar(this.myBuilder(1, '组件2')) TabContent() { Text('组件3内容').width('100%').textAlign(TextAlign.Center) }.tabBar(this.myBuilder(2, '组件3')) TabContent() { Text('组件4内容').width('100%').textAlign(TextAlign.Center) }.tabBar(this.myBuilder(3, '组件4')) TabContent() { Text('组件5内容').width('100%').textAlign(TextAlign.Center) }.tabBar(this.myBuilder(4, '组件5')) TabContent() { Text('组件6内容').width('100%').textAlign(TextAlign.Center) }.tabBar(this.myBuilder(5, '组件6')) TabContent() { Text('组件7内容').width('100%').textAlign(TextAlign.Center) }.tabBar(this.myBuilder(6, '组件7')) } .vertical(false) //导航栏滑动方向 - 默认值 .scrollable(true) //开启/关闭滑动切换 - 默认值 .animationDuration(0) //切换动画时长 .barMode(BarMode.Scrollable) //设置导航栏可滑动 .onChange((index: number) => { //返回当前所在页面的索引 this.selectIndex = index; }) } } ``` #### class类 ```TypeScript //class class Person { name: string = ' '; //必须有初始值 age: number = 0; sex?: 'Man' | 'Women' //名称后面加'?'表示可选属性,可以不设置初始值 static personNum: number = 0; //静态属性 protected resource: boolean = true; //受保护的变量,仅可在类内或者子类内访问 //有构造函数时,上述声明可不用初始化 constructor(personName: string, num: number,) { this.name = personName; this.age = num; Person.personNum++; } //声明类函数 sayHello(personName: string) { console.log(`你好${personName},我是${this.name}`); } //静态函数 static getPersonNum(): number { return Person.personNum; } } //如属性值太多,参数较为复杂时,可通过新声明interface接口的方式简化语句 let p: Person = new Person('张三', 18); console.log(`${p.sex?.length}`); //如需要使用(访问)可选属性,建议使用可选链操作符`?.`以防止出错 p.sex = 'Man'; console.log(`${p.sex?.length}`); p.sayHello('李四'); //调用类函数 console.log(`当前人数为:${Person.getPersonNum()}`) //调用静态函数 console.log(`当前人数为:${Person.personNum}`) //调用静态属性 class Student extends Person { //Student类为Person类的子类 public grade: number = 0; //公有属性 readonly sex: 'Man' | 'Women' | undefined = 'Man'; //只读属性 private deposit: number = 10; //私有属性,不能在类外访问(包括子类) //如需重写父类中的函数,则可直接在子类中重写同名函数 sayHello(personName: string) { console.log(`你好${personName},我是学生${this.name}`); console.log(`仅能在类内访问private变量${this.deposit}`); console.log(`子类可访问父类的protected变量:${super.resource}}`); } //使用`super`关键字可以访问父类的实例字段、方法和构造函数 constructor(name: string, age: number, grade: number, sex: 'Man' | 'Women' | undefined) { super(name, age) this.grade = grade; } } let s1: Student = new Student('王五', 7, 4, 'Man'); s1.sayHello('赵六'); console.log(`${s1.name}目前在读${s1.grade}年级`); console.log(`当前人数为:${Person.personNum}`) //派生类新建对象时,也会调用基类的构造函数 console.log(`typeof可返回简单参数的类型:${typeof true}`) console.log(`typeof可返回简单参数的类型:${typeof 1}`) console.log(`typeof可返回简单参数的类型:${typeof 's'}`) console.log(`instanceof可判断对象是否为传入的类或父类生成的:${s1 instanceof Person}`) console.log(`instanceof可判断对象是否为传入的类或父类生成的:${s1 instanceof Student}`) // s1.sex = 'Man'; //Cannot assign to 'sex' because it is a read-only property console.log(`${s1.name}的性别为:${s1.sex}`) ``` #### 剩余参数和展开运算符 ```TypeScript //剩余参数和展开运算符 function sumAnArray(n1: number, ...numArray: number[]): number { let sum = n1; if (numArray.length != 0) { for (let arr of numArray) { sum += arr; } } return sum; } console.log(`${sumAnArray(1, 1, 2, 3, 5)}`) let arr1: number[] = [1, 2, 3] let arr2: number[] = [4, 5, 6] //将arr1数组的尾端上,加上arr2数组 let newArr: number[] = [...arr1, ...arr2] console.log('newArr = ',newArr); ``` #### 接口补充 ```TypeScript //接口补充 //1.接口继承 interface Person { name: string; } interface Student extends Person { IDNumber: number; } const s1: Student = { name: '张三', IDNumber: 1 }; console.log(`姓名:${s1.name},ID = ${s1.IDNumber}`); //2.接口实现--定义一个interface来约束类,被约束的类要按照interface要求,实现类的主体 interface Interface001 { variable001: string; variable002: number; variable003: boolean; func001: () => void; } class Class001 implements Interface001 { //必须含有Interface001接口中所有主体 variable001: string; variable002: number; variable003: boolean; variable004: boolean = true; //可以扩展Interface001接口中没有的内容 constructor(variable001: string, variable002: number, variable003: boolean) { this.variable001 = variable001; this.variable002 = variable002; this.variable003 = variable003; } func001() { } } let variable1: Class001 = new Class001('string', 123, false); console.log(`${variable1}`) ``` #### 泛型函数 ```TypeScript //泛型函数——调用函数时,可以传递形参类型,使函数的返回值、形参类型可变 //1.声明 function fun01(v: Type): Type { return v; } //2.调用 console.log(`${fun01(1)}`) console.log(`${fun01('泛型函数可省略形参类型,会自动识别')}`) //返回传入数组的长度 function getArrLength(arr: T[]): number { return arr.length; } console.log(`${getArrLength([1, 2, 3, 4, 5, 6])}`) //获取传入数组的最后一项 function getsTheEndItemOfTheArray(v: Type[]): Type { return v[v.length-1] } console.log(`${getsTheEndItemOfTheArray([2, 3, 5, 7, 9, 10])}`) //3.泛型约束——给传入类型加上限制 interface RestrictionOfFunc02 { length: number } function func02(item: T): void { //T继承于RestrictionOfFunc02 console.log(`${item.length}`); } func02('abc'); func02([1, 2, 3]) // func02(0); //ERROR: Type 'number' does not satisfy the constraint 'RestrictionOfFunc02' //4.多个泛型参数 function func03(t1: T1, t2: T2): void { console.log('', t1); console.log('', t2); } func03('年龄', 18) ``` #### 泛型接口、类 ```TypeScript //泛型接口、类 // 1.声明 interface IDFunc { id: (value: T) => T; ids: () => T[]; } //2.实例化 let obj: IDFunc = { id(value: number): number { return value; }, ids(): number[] { return [1, 2, 3]; } } //泛型类 // 1.声明 class MyClass { name: T constructor(name: T) { this.name = name; } } //2.实例化 let c1 = new MyClass('张三'); console.log(`${c1.name}`); ``` #### 模块化语法 `Index.ets` ```TypeScript //模块化语法 // 1.默认导出——默认导出一个值或对象。使用时,可以自定义导入名称。 //导入路径`../Tools/Module_1`文件的默认导出变量variable01,并使用Module_1_variable01关键字来使用它 //"import" statements after other statements are not allowed import Module_1_variable01 from '../Tools/Module_1' import { variable01, variable02, variable03, variable04, variable05 as num05, variable06 } from '../Tools/Module_2' //一次性导入 import * as Module3Data from '../Tools/Module_3' console.log(`${Module_1_variable01}`); //使用导入后的数据 //按需导入 //使用导入后的数据 console.log(`variable01 = ${variable01}`); console.log(`variable02 = ${variable02}`); console.log(`variable03 = ${variable03}`); console.log(`variable04 = ${variable04}`); console.log(`num05 = ${num05}`); //可以自定义导入后名称 console.log(`variable06 = ${variable06}`); //全部导入 //使用导入后的数据 console.log(`Module3Data.M_31 = ${Module3Data.M_31}`); ``` `Module_1` ```TypeScript //每个.ets文件就是一个模块,每个模块之间相互独立 let variable01: number = 0; export default variable01; //默认导出variable01变量 ``` `Module_2` ```TypeScript //逐个导出模块中的数据 export let variable01: number = 0; export let variable02: number = 0; export let variable03: number = 0; //一次性导出模块中的数据 let variable04: number = 0; let variable05: number = 0; let variable06: number = 0; export { variable04, variable05, variable06 }; ``` `Module_3` ```TypeScript //全部导出 export let M_31: number = 0; export let M_32: number = 0; export let M_33: number = 0; export let M_34: number = 0; ``` #### 自定义组件 ```TypeScript //自定义组件 //Doc URL: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/4_23_u81ea_u5b9a_u4e49_u7ec4_u4ef6-V5 import { MyComponent2 as ComponentMyComponent2 } from '../Components/Component1'; @Component struct MyComponent1 { @State num: number = 1; //成员变量 getMore = () => { //成员变量 } sayHi() { //成员函数 AlertDialog.show({ message: 'sayHi' }) } build() { Column({ space: 10 }) { Text(`Text组件MyComponent${this.num}自定义组件中`).border({ width: 1 }).padding(10) Button(`Button组件MyComponent${this.num}自定义组件中`) .onClick(() => { this.sayHi() this.getMore() }) }.width('100%') } } @Entry @Component struct Index { build() { Column({ space: 10 }) { MyComponent1()//渲染MyComponent1自定义组件 .width('100%') //自定义组件可以添加通用属性和方法 //支持传参 MyComponent1({ num: 2, getMore() { AlertDialog.show({ message: 'getMore' }) } }) ComponentMyComponent2() //支持从其他文件导入 } } } ``` #### @BuilderParam传递UI ```TypeScript //@BuilderParam传递UI //Doc URL:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-builderparam-V5#%E5%88%9D%E5%A7%8B%E5%8C%96builderparam%E8%A3%85%E9%A5%B0%E7%9A%84%E6%96%B9%E6%B3%95 @Component struct SonComponent { @BuilderParam ContentBuilder: () => void = this.defaultBuilder; @Builder defaultBuilder() { //默认构建内容 Text('默认值') } build() { Column() { this.ContentBuilder(); } } } @Entry @Component struct Index { build() { Column() { SonComponent() //显示默认内容 SonComponent() { //显示子组件内容 Text('当自定义组件存在子组件时,defaultBuilder内容则不会显示') } }.width('100%').height('100%') } } ``` #### 多个@BuilderParam参数 ```TypeScript //多个@BuilderParam参数 //Doc URL:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-builderparam-V5#%E5%88%9D%E5%A7%8B%E5%8C%96builderparam%E8%A3%85%E9%A5%B0%E7%9A%84%E6%96%B9%E6%B3%95 @Component struct MyCard { @BuilderParam titleBuilder: () => void = this.titleDefaultBuilder; @BuilderParam contentBuilder: () => void = this.contentDefaultBuilder; @Builder titleDefaultBuilder() { Text('默认标题') } @Builder contentDefaultBuilder() { Text('默认内容') } build() { Column() { //标题部分 Row() { this.titleBuilder(); }.height(30).width('100%').border({ width: { bottom: 1 }, color: '#ccc' }).padding({ left: 10 }) //内容部分 Row() { this.contentBuilder(); }.width('100%').padding(10) }.borderRadius(10).backgroundColor(Color.White).margin(10).height(100) } } @Entry @Component struct Index { @Builder fatherTitleDefaultBuilder() { Text('传入的标题') } @Builder fatherContentDefaultBuilder() { Text('传入的内容') } build() { Column() { MyCard() MyCard({ titleBuilder: this.fatherTitleDefaultBuilder, contentBuilder: this.fatherContentDefaultBuilder }) }.backgroundColor('#ccc').width('100%').height('100%') } } ``` #### 状态管理 ```TypeScript //状态管理 interface Car { brand: string } interface Person { name: string carName: Car //二级嵌套 } @Entry @Component struct Index { @State p: Person = { name: '张三', carName: { brand: 'XiaoMi' } } build() { Column({ space: 10 }) { Text(`${this.p.name}拥有${this.p.carName.brand}品牌的车`).fontSize(20).fontWeight(FontWeight.Bold) Button('换车').width(100) .onClick(() => { this.p.carName.brand = 'BMW'; //二级嵌套的修改,不会引起UI渲染 console.log(`this.p.carName.brand = ${this.p.carName.brand}`); //值已修改 }) Button('换车').width(100) .onClick(() => { this.p.carName = { brand: 'BMW' }; //成功进行UI渲染 console.log(`this.p.carName.brand = ${this.p.carName.brand}`); //值已修改 }) }.width('100%') } } ``` #### @prop ```TypeScript //@prop——父子单向同步 //Doc URL: https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V13/arkts-prop-V13 @Component struct SonComponent { @Prop SonData: number = 0; //随着父组件数据一起变化 build() { Column({ space: 30 }) { Text('SonComponent').fontSize(20).fontWeight(FontWeight.Bold) Text(`SonData = ${this.SonData}`).fontSize(20) Button('SonData++') .onClick(() => { this.SonData++; //一般的,不在子组件中修改@Prop修饰的数据 }) }.width(300).height(200).border({ width: 1 }).padding(10).backgroundColor(Color.Orange) } } @Component struct FatherComponent { @State fatherData: number = 0 build() { Column({ space: 30 }) { Text('FatherComponent').fontSize(20).fontWeight(FontWeight.Bold) SonComponent({ SonData: this.fatherData }) //将父组件数据传给子组件 Text(`FatherComponent = ${this.fatherData}`).fontSize(20) Button('FatherComponent ++').width(300) .onClick(() => { this.fatherData++; }) }.width('100%').height(500).border({ width: 1 }).padding(10).backgroundColor(Color.Pink) } } @Entry @Component struct Index { build() { Column() { FatherComponent(); }.width('100%').height('100%') } } ``` #### 掘金评论 `Index.ets` ```TypeScript //掘金评论案例 import PageHeader from '../Components/PageHeader' import PageContent from '../Components/PageContent' import PageBottom from '../Components/PageBottom' import font from '@ohos.font'; import { ReviewData, testData } from '../Model/ReviewData' @Entry @Component struct Index { aboutToAppear(): void { font.registerFont({ familyName: 'myFont', familySrc: '/Fonts/iconfont.ttf' }) } @State commentList: ReviewData[] = testData(); //点赞 handleLike(index: number) { // AlertDialog.show({ message: index.toString() }) let itemData = this.commentList[index]; if ( itemData.isLike) { itemData.likeNumber--; } else { itemData.likeNumber++; } itemData.isLike = !itemData.isLike; this.commentList.splice(index, 1, itemData) } build() { Column() { //Head PageHeader() //Content //list Doc URL: https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/ts-container-list-V5 List() { ForEach(this.commentList, (arr: ReviewData, index: number) => { ListItem() { PageContent({ arrItem: arr, onLikeClick: (index: number) => { this.handleLike(index) }, index }) } }) } .layoutWeight(1) .width('100%') .padding({ bottom: 10 }) //Bottom PageBottom(); }.width('100%').height('100%') } } ``` `PageBottom.ets` ```TypeScript @Component struct PageBottom { build() { Row() { Row() { Text('\ue60f').fontFamily('myFont').fontSize(18).margin({ left: 20 }) TextInput({ placeholder: '写评论...' }).backgroundColor(Color.Transparent).fontSize(18) } .height(40) .backgroundColor('#f5f6f5') .borderRadius(20) .margin({ left: 15, right: 20, top: 10, bottom: 10 }) .layoutWeight(1) Text('\ue8ad').fontFamily('myFont').fontSize(26).margin({ left: 6, right: 6 }) Text('\ue665').fontFamily('myFont').fontSize(26) }.height(60).width('100%') } } export default PageBottom; ``` `PageContent.ets` ```TypeScript import { ReviewData } from '../Model/ReviewData' @Component struct PageContent { @Prop arrItem: ReviewData @Prop index: number onLikeClick = (index: number) => { } build() { Column() { //用户信息 Row() { Image(this.arrItem.avatar).width(30).aspectRatio(1).margin({ top: 10 }).borderRadius(15) Text(this.arrItem.username).fontSize(13).fontColor(Color.Gray).margin({ top: 10, left: 8 }) Image(this.arrItem.convertLevel(this.arrItem.userLevel)).width(20).aspectRatio(1).margin({ top: 10, left: 8 }).borderRadius(15) } //评论内容 Text(this.arrItem.commentContent).fontSize(13).fontColor(Color.Black).margin({ left: 40, top: 0, bottom: 8 }) //评论数据 Row() { Text(this.arrItem.convertTime(this.arrItem.commentReleaseTime)).fontSize(11).fontColor(Color.Gray) Row({ space: 5 }) { Image(this.arrItem.isLike ? $r('app.media.like_select') : $r('app.media.like_unselect')).width(15).aspectRatio(1) Text(this.arrItem.likeNumber.toString()).fontSize(11).fontColor(this.arrItem.isLike ? Color.Blue : Color.Gray) }.onClick(() => { this.onLikeClick(this.index); }) }.padding({ left: 40, top: 5 }).width('100%').justifyContent(FlexAlign.SpaceBetween) }.padding({ left: 15, right: 15 }).alignItems(HorizontalAlign.Start) } } export default PageContent; ``` `PageHeader.ets` ```TypeScript @Extend(Button) function highlightButton(isHighlightButton: boolean) { .width(46) .height(32) .fontSize(12) .padding({ left: 5, right: 5 }) .backgroundColor(isHighlightButton ? '#fff' : '#F7F8FA') .fontColor(isHighlightButton ? '#2f2e33' : '#8e9298') .border({ width: 1, color: isHighlightButton ? '#e4e5e6' : '#F7F8FA' }) } @Component struct PageHeader { @State isHighlightButton: boolean = true; build() { Row() { Text('全部评论').fontColor('#222').fontSize(20).fontWeight(FontWeight.Bold) Row() { Button('最新', { stateEffect: false }).highlightButton(this.isHighlightButton) .onClick(() => { this.isHighlightButton = true; }) Button('最热', { stateEffect: false }).highlightButton(!this.isHighlightButton) .onClick(() => { this.isHighlightButton = false; }) } .backgroundColor('#F7F8FA') .borderRadius(20) }.width('100%') .justifyContent(FlexAlign.SpaceBetween) .padding(16) } } export default PageHeader; ``` `ReviewData.ets` ```TypeScript export class ReviewData { avatar: string //头像 username: string //用户名 userLevel: number //用户等级 likeNumber: number //点赞数 commentContent: string //评论内容 isLike: boolean //是否点赞 levelIcon: Resource //level等级 differentialTime: string //发布时间与当前时间差值 commentReleaseTime: number //评论发布时间 constructor(avatar: string, username: string, commentContent: string, isLike: boolean, commentReleaseTime: number) { this.avatar = avatar; this.username = username; this.userLevel = Math.floor(Math.random() * 6); this.likeNumber = Math.floor(Math.random() * 100); this.commentContent = commentContent; this.isLike = isLike; this.levelIcon = this.convertLevel(this.userLevel); this.commentReleaseTime = commentReleaseTime; this.differentialTime = this.convertTime(commentReleaseTime); } //返回用户等级对应的等级图标路径 convertLevel(userLevel: number) { const picturePath = [ $r('app.media.level_1'), $r('app.media.level_2'), $r('app.media.level_3'), $r('app.media.level_4'), $r('app.media.level_5'), $r('app.media.level_6') ] return picturePath[userLevel] } convertTime(commentReleaseTime: number) { const presentTime = new Date().getTime(); //获取当前时间 const differentialTime = (presentTime - commentReleaseTime) / 1000; //发布至今的时间差(s) if (differentialTime < 5 || differentialTime == 0) { return "刚刚"; } else if (differentialTime < 60) { return `${Math.floor(differentialTime)}秒前`; } else if (differentialTime < 3600) { return `${Math.floor(differentialTime / 60)}分钟前`; } else if (differentialTime < 86400) { return `${Math.floor(differentialTime / 3600)}小时前`; } else if (differentialTime < 604800) { return `${Math.floor(differentialTime / 86400)}天前`; } else if (differentialTime < 2592000) { return `${Math.floor(differentialTime / 604800)}周前`; } else if (differentialTime < 31536000) { return `${Math.floor(differentialTime / 2592000)}个月前`; } else { return `${Math.floor(differentialTime / 31536000)}年前`; } } } //测试数据 export const testData = (): ReviewData[] => { let testingDataset: ReviewData[] = new Array(); testingDataset = [ new ReviewData(`https://fastly.picsum.photos/id/770/600/600.jpg?hmac=tuK9EHg1ifTU3xKAiZj2nHSdWy4mk7enhylgOc2BW7E`, '雪山飞狐', '23年一年干完的事😂😂😂真的非常仓促', false, 1645820201123), new ReviewData(`https://fastly.picsum.photos/id/225/600/600.jpg?hmac=v97zt_t4mxeyMttX_m09pxhCvftiTxFR1MMBZi5HQxs`, '千纸鹤', 'Netty对象池源码分析来啦!欢迎点赞[奸笑]', false, 1677356201123), new ReviewData(`https://fastly.picsum.photos/id/122/600/600.jpg?hmac=1oA93YbjYVt96DcJcGQ5PLthzjUsdtrnBQaM0USBozI`, '烟雨江南', '有一个不听劝的Stable Diffusion出图的小伙伴,找我给她装填脑。 一个资深的IT工程师不能受这个委屈。', false, 1688772201123), new ReviewData(`https://fastly.picsum.photos/id/654/600/600.jpg?hmac=ewnK6Bx_MKQLJa9waZOV1xNO7--K5oSwCShtz1JDYw8`, '魔法小精灵', '有一点可以确信 前后端开发界限越来越模糊。后端可以不写 但是不能不会。', false, 1697484201123), new ReviewData(`https://fastly.picsum.photos/id/345/600/600.jpg?hmac=EQflzbIadAglm0RzotyKXM2itPfC49fR3QE7eW_UaPo`, '独行侠', '今天看到一个帖子,挺有意思的', false, 1704067200000), new ReviewData(`https://fastly.picsum.photos/id/905/600/600.jpg?hmac=DvIKicBZ45DEZoZFwdZ62VbmaCwkK4Sv7rwYzUvwweU`, '枫叶飘零', '我想了搞钱的路子, 1:投资理财, 后来发下,不投资就是最好的理财, 2:买彩票,后来发现彩票都是人家预定好的,根本不是随机的,卒, 3:开店创业,隔行如隔山,开店失败,卒。', false, 1706745600000), new ReviewData(`https://fastly.picsum.photos/id/255/600/600.jpg?hmac=-lfdnAl71_eAIy1OPAupFFPh7EOJPmQRJFg-y7lRB3s`, '星空漫步', '优胜劣汰,自然选择吧,没什么好怪的。都是crud,招个大学生就能干了。', false, 1707523200000), new ReviewData(`https://fastly.picsum.photos/id/22/600/600.jpg?hmac=QEZq7KUHwBZCt3kGSEHMwJlZfnzCxCeBgHjYj7iQ-UY`, '剑指苍穹', '白嫖ChatGPT4的功能。然后,抱着试一试的态度把玩了一下。发现真的好用。', false, 1708300800000), new ReviewData(`https://fastly.picsum.photos/id/439/600/600.jpg?hmac=LC9k_bzrN0NhKRyV62fou3ix3cRFZKNfAyXgxGs6zh8`, '黑暗王国', '字数越少,事情越大', false, 1708646400000) ] return testingDataset; } ```