//定义教举 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') } } // 初始化对象 let a:A = new B() //调用方法,传递枚举参数 a.say(Msg.HI)
// 定义矩形类 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)模块可以相互加载,提高代码复用性
//定义矩形类,并通过export 导出 export class Rectangle { //成员变量 public width: number public length: number //构造函数 constructor(width: number, length: number){ this.width = width this.length = length } } // 定义工具方法,求矩形面积,并通过export导出 export function area(rec: Rectangle): number{ return rec.width * rec.length }
使用
//通过import语法导入,from后面写文件的地址 import {Rectangle, area] from '../rectangle // 创建Rectangle对象 let r = new Rectangle(10, 20) // 调用area方法 console.log('面积为: + area(r))
快速入门鸿蒙开发
创建项目
1.打开DevEco Studio开发工具
2.点击create Project
3.这里演示选择Empty Ability即可
4.点击Next
5.修改配置(下方有配置解释,根据项目需求进行更改)
6.点击finish即可创建项目
创建项目的配置介绍
Project name: 项目名 Bundle name: 包名,需要遵循com.jwz.项目名 这种规范,需要保证包名唯一 Save location: 项目保存路径 Compile SDK: SDK的版本(选择默认的就行) Model: 选择默认的Stage就行 Enable Super Visual: (这里不用动) Language: 开发语言需要勾选ArkTs(默认也是勾选) Compatible SDK: 这个版本和上面一样,默认就行 Device type: 设备类型:Phone(手机) Tablet(平板),这两个可以都勾选
项目的各文件介绍
项目结构如下:
各个文件介绍:
- 根目录下的几个文件均是配置文件,这个不用我们深入了解,重点关注的是文件夹带蓝色小方块的entry这个文件夹,这是项目入口模块(也叫: 入口Ability)
- 展开entry,在路径下也是一堆配置文件,这个我们无须担心,重点关注src文件夹即可(需要了解这些配置信息可以查看官方文档,有详细介绍,点击链接直达)
- 展开src文件夹有main(开发用的)和ohosTest(测试用的,我们无需关心),我们展开main即可
- 展开main文件夹,同样有个json5后缀的配置文件(先不管),重点看另外两个ets和resources
- resources资源文件夹,默认里面有个国际化配置(en_US和zh_CN),继续展开base里面的media可以看到里面的icon图标,这里是存放所有的静态资源的
- ets文件夹展开里面有两个文件夹,其中pages就是鸿蒙软件的每个页面的代码存放了,展开发现有个index.ets,这个就是默认展示的页面了,将来会写更多的ets文件,就是更多的手机页面了
运行项目
点击软件右边的Previewer生成一个预览设备(首次展开会弹出欢迎界面,叉掉在进来就可以了)
这样,预览设备上面的页面就是我们index.ets文件代码编译出来的页面了
详解index.ets代码的含义
// @Entry @Component @State 装饰器: 用来装饰类结构、方法、变量 @Entry // 标记当前组件是入口组件,当页面跳转到新页面,则新页面也属于入口组件,当页面内引用别的自定义组件,则此自定义组件非入口组件 @Component //标记自定义组件 struct Index { // struct 自定义组件:可复用的UI单元 // @State 在开头讲过了,标记该变量是状态变量,值变化时会总发UI刷新 @State message: string = 'Hello World' build() { // build UI描述: 其内部以声明式方式描达UI结构 // Row Column Text等,都是内置组件: ArkUI提供的组件
//组件分类: //容器组件:用来完成页面布局,例如 Row、Column //基础组件:自带样式和功能的页面元素,例如 Text Row() { Column() { Text(this.message) .fontSize(50) .fontWeight(FontWeight.Bold) //字体加粗 .onClick(()=>{ // 事件方法:设置组件的事件回调 // 处理相关事件 console.log('111') // 这个打印语句在下面控制台点击log那里可以看到 this.message = 'hello 萧寂173' //修改内容 }) } .width('100%') } .height('100%') // fontSize fontWeight width height 属性方法: 设置组件的UI样式 } }
效果图
ArtUI
ArkUl的各种组件
Image组件
Image:图片显示组件 1 声明Image组件并设置图片源: Image(src: string|PixlMap|Resource)
1-1.string格式,通常用来加载网络图片,需要申请网络访问权限: ohos.permission.INTERNET(注意,在模拟器可以正常访问网络图片,在真实设备上需要申请网络访问权限) Image('https://xxx .png') 1-2.PixelMap格式,可以加载像素图,常用在图片编辑中 Image(pixelMapobject) // 直接操作像素,使用比较繁琐,需要构建其对象再传给image 1-3.Resource格式,加载本地图片,推荐使用 Image(rawfile( 'mate60.png')) //访问的是entry.src.main.resources.rawfile文件夹内的图片,直接指定图片名,这里后缀名不能省略
2.添加图片属性(width,height,borderRadius为组件通用属性,interpolation只能在图片组件使用) Image($r( 'app.media,icon' )).width(100) // 宽度 .height(120) // 高度 .borderRadius(10) // 边框圆角 .interpolation(ImageInterpolation.High) // 图片插值,当低分辨率图片放大会有很多锯齿,设置插值会把这些锯齿弥补起来,看起来清晰度会清晰,有高中低三个选择,这里选择了高
3.完整代码 @Entry @Component struct Index { @State message: string = 'Hello World'
build() { Row() { Column() { Image('img-home.csdnimg.cn/images/2023…) // 可以用百分比,也可以用数字(默认带vp参数,虚拟像素,会根据设备像素密度进行换算,可以保证同一个元素在不同设备上视觉大小是统一的,类似于rpx,rem) Image($r('app.media.icon')).width(250).interpolation(ImageInterpolation.High) } .width('100%') } .height('100%') } }
网络授权
申请网络访问权限文档:
在main/module.json5文件的module下面加入下面属性和值即可
"requestPermissions": [ { "name": "ohos.permission.INTERNET" } ],
Text组件
Text:文本显示组件 1.声明Text组件并设置文本内容 Text(content?: string|Resource)
1-1:string格式,直接填写文本内容 Text('图片宽度') 1-2:Resource格式,读取本地资源文件 // 限定词目录存放的是国家,语言,设备等信息 // app.为固定前缀,string代表限定词目录(zh_CN和en_US)下的string.json(即国际化语言),width_label为string.json内name属性所对应的值 // 注意 同级的base目录下有个element文件夹,里面也有个string.json,这个文件是默认文件,当限定词在中英文里面都没有匹配的会来这里找(这里是默认的,不限于中英文),因此如果需要添加限定词,则这三个文件夹都需要改动 Text($r('app.string.width_label'))
2.添加文本属性 Text('注册账号') .lineHeight(32) // 行高 .fontsize(20) // 字体大小 .fontColor('#ff1876f8') // 字体颜色. .fontWeight(FontWeight.Medium) // 字体粗细
3.完整代码 @Entry @Component struct Index { @State message: string = 'Hello World' build() { Row() { Column() { Text($r('app.string.module_desc')) .fontSize(25) // 设置字体大小 .fontWeight(FontWeight.Bold) // 字体加粗 } .width('100%') } .height('100%') } }
TextInput组件
TextInput:文本输入框 1.声明TextInput组件: TextInput( {placeholder?: ResourceStr, text?: ResourceStr}) 1-1:placeHoder:输入框无输入时的提示文本 TextInput({placeholder:请输入账号或手机号"}) 1-2:text:输入框当前的文本内容 TextInput({text:'itcast'})
2.添加属性和事件 TextInput({text:'当前输入文本' }) .width(150) // 宽 .height(30) //高 .backgroundColor('#FFF') // 背景色 .type(InputType.Password) // 输入框类型 .onChange(value=>{ // 输入框改变时触发,value为输入框的值 console.log(value) })
3.完整代码 @Entry @Component struct Index { @State message: string = 'Hello World'
build() { Row() { Column() { TextInput({text:'当前输入文本' }) .width(150) // 宽 .height(30) //高 .backgroundColor('#FFF') // 背景色 .type(InputType.Password) // 输入框类型 .onChange(value=>{ console.log(value) }) } .width('100%') } .height('100%') } }
Button组件
Button:按钮组件 1.声明Button组件,label是按钮文字: Button(label?: ResourceStr)
1-1:文字型按钮 Button('点我') 1-2:自定义按钮,在Button内嵌套其它组件 Button(){ Image($r('app.media.search' )) .width(20) .margin(10) }
2.添加属性和事件 Button('点我') .width(100) .height(30) .type(ButtonType.Normal) // 按纽类型 .onClick(() => { // 处理点击事件 }
Slider组件
slider:滑动条组件 Silder (options?: SliderOptions )
Slider({ min: 0,// 最小值 max: 10,// 最大值 value: 30,// 当前值 step: 0.1,// 滑动步长 style: SliderStyle.OutSet,// 决定滑块在里面还是外面 direction: Axis.Horizontal, // Vertical(垂直) 滑块方向(水平和垂直) reverse: false // 是否反向滑动 }) .width('90%') // 需要字符串百分比 .trackThickness(5) // 决定滑块粗细 .showTips(true) // 是否展示value百分比提示 .blockColor('#36d') // 滑块背景色 .onChange(value=>{ // value就是当前滑块值 })
Column和Row组件
列就是Column容器,行就是Row容器
| 属性方法名 | 说明 | 参数 |
|---|---|---|
| justifyContent | 设置子元素在主轴方向的对齐格式 | FlexAlign枚举 |
| alignItems | 设置子元素在交叉轴方向的对齐格式 | Row容器使用VerticalAlign枚举,Column容器使用HorizontalAlign枚举 |
案例代码
@Entry @Component struct Index { @State imagewidth: number = 30 // 定义图片宽度
build() { Column({space:20}){ // space 间距 Text('item1') Text('item2') Text('item3') Text('item4') } .width('100%') .height('100%') .justifyContent(FlexAlign.Center) // 对齐方式 .alignItems(HorizontalAlign.Center) // 交叉轴对齐方式 .layoutWeight(1) // 剩余空间分配(默认都是0,使用自己设置的宽高,设置为1之后,除了其他元素自身设置的宽高以外,其他的给设置为1的元素均匀分配,类似于html的flex:1) } }
分割线组件
Divider() // 放到两个组件之间,会出现一条线,作用等同于html的hr标签
撑满容器组件
Blank() // 在容器内部,其他组件都占满了一定空间,在两个组件之间加入blank可以直接将两个组件撑到最边上
List组件
列表(List)是一种复杂容器,具备下列特点:
1.列表项(ListItem)数量过多超出屏幕后,会自动提供滚动功能
2.列表项 (ListItem)既可以纵向排列,也可以横向排列
@Entry @Component struct Index {
build() { List({space:80}){ ForEach([1,2,3,4,5,6,7,8,9,10,11,12,13],item=>{ ListItem(){ // 列表项内容,只能包含一个根组件 // 超出屏幕会显示滚动条 Text("ListItem") } }) } .width('100%') .listDirection(Axis.Vertical) // 列表方向,Horizontal:水平,默认纵向(Vertical:垂直) } }
自定义组件
简单来说每个页面都是一个自定义组件,都有@component和@Entry修饰,但是@Entry标记当前自定义组件为入口组件,也就是页面组件,不能进行复用,则如果需要可复用的组件只需要把@Entry删除即可让组件可以进行复用
在同一个组件内部
// 子组件 @Component struct Header{ @State message:string=''; // 接收父组件参数 build(){ Text(this.message) // 使用参数 } }
// 父组件 @Entry @Component struct Index { build() { Row() { Header({message:'123'}) // 传值给子组件 } .height('100%') } }
定义在单独文件内,供全局使用
在ets下新建个components文件夹
在components下新建Header.ets文件,内容如下
// 子组件 @Component export struct Header{ @State message:string=''; build(){ Text(this.message) } }
在任意需要的父组件内使用
import {Header} from '../components/Header' // 父组件 @Entry @Component struct Index { build() { Row() { Header({message:'1234'}) } .height('100%') } }
自定义构建函数
全局
与自定义组件类似,但是这是一个函数,可以将组件中重复的代码封装到一个函数中,在需要的地方直接调用,不需要return返回
@Builder function xj(aaa:string){ Text(aaa) // 页面会显示'111222' }
// 父组件 @Entry @Component struct Index { build() { Row() { xj('111222') } .height('100%') } }
局部
// 父组件 @Entry @Component struct Index { build() { Row() { // 局部定义需要添加this关键字才能调用 this.xj('111222') } .height('100%') }
// 在局部定义不需要function关键字 @Builder xj(aaa:string){ Text(aaa) // 页面会显示'111222' } }
通用样式的设置
全局公共样式函数
// 定义全局公共样式函数 @Styles function xj(){ .height('100%') }
@Entry @Component struct Index { build() { Row() { Text('你好') } .xj() // 使用公共样式函数 } }
局部公共样式函数
@Entry @Component struct Index { // 定义局部样式函数 @Styles xj(){ .height('100%') } build() { Row() { Text('你好') } .xj() // 使用局部样式函数,这个不用加this } }
特殊样式(组件独有的样式,非公共样式)函数的封装
这种样式只能写在全局,没有局部
// 定义组件独有的样式函数 // 使用Extend继承,参数为继承的组件 @Extend(Text) function xj(){ .fontColor('#f36') .fontSize(18) }
@Entry @Component struct Index { build() { Row() { Text('你好') .xj() //使用 } } }
ArkUI的循环控制以及条件渲染
@Entry @Component struct Index { @State items:any[]=[ {id:1,name:'华为Mate60',image:'1.jpg',price:6999,discount:1}, {id:2,name:'华为X50',image:'2.jpg',price:8799,discount:0}, {id:3,name:'小米14',image:'3.jpg',price:4379,discount:0}, {id:4,name:'OPPOFind12',image:'4.jpg',price:3299,discount:1}, {id:5,name:'荣耀100',image:'5.jpg',price:3799,discount:1} ]
build() { Column(){ ForEach( this.items, (item,index)=>{ Row(){ if(item.discount){ // 条件控制,为0代表下架,也就是条件渲染 Text(index.toString()) // 数字要转成字符串,否则不显示 Image(item.image) // 因为类型是any,所以这里没提示,很正常 .width(100) Column(){ Text(item.name) Text(item.price.toString()) // 数字要转成字符串,否则不显示 } .height(100) }else{ Text('此商品已下架') } } }, (item,index)=>{ // foreact的第三个参数也可以不写,内部在循环时做好了key的处理 return item.id.toString() // 返回值为字符串,表示唯一性,类似于key } ) } } }
对象类型和类
使用@State监控对象类型
// 定义类,类里面为对象属性 class Person{ name:string age:number
constructor(name:string,age:number) { this.name=name this.age =age } }
@Entry
@Component
struct Index {
@State p:Person = new Person('Jack',21)
// 下面这种是数组的写法
// @State p:Array = [new Person('Jack',21),new Person('Jack1',22),new Person('Jack2',23)]
build() {
Row() {
Text(姓名: ${this.p.name},年龄: ${this.p.age})
.onClick(()=>{
this.p.age+=1
})
}
}
}
对象内部嵌套对象写法
// 定义类,类里面为对象属性 class Person{ name:string age:number gf:Person // 第三个可有可无,需要用?判断 constructor(name:string,age:number,gf?:Person) { this.name=name this.age =age this.gf = gf } }
@Entry @Component
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!