鸿蒙4.0基础开发教程

2023-12-25 10:55:46

开发准备

ArkTS语言

ArkTs语言文档

例如在页面做个按钮并带有点击效果需要html,css,js共同完成
html(按钮标签)-css(按钮样式)-js(控制按钮点击操作)

当学完了ArkTs即可以同时完成html+css+js的所有功能了
只需要ArkTs这一种语言就够了

如下,使用ArkTs完成创建按钮并设置按钮样式和点击操作的代码

@State times:number = 0 //定义变量 @State监视这个变量,类似vue的属性监听,或者也可当做响应式变量,即如果不加@State,则页面不会重新渲染,变量的改变不会被监听到
build(){ // build方法代表构建页面的方法
	Row(){ //将按钮声明为一行
		Button(`点我${this.times}`) // 在页面渲染出按钮元素
		   .backGroundColor('#36D') // 设置按钮背景颜色
		   .onClick(()=>this.times++)  // 按钮点击事件
	}
	.width('100%') // 将当前行的宽设置为100%
	.justifyContent(FlexAlign.Center) // 对齐模式:居中
}

这里补充下间距
padding(20) 上下左右都是20
padding({left:20}) 只有左边是20
margin也是同理

TypeScript语法

变量声明

TypeScript在JavaScript的基础上加入了静态类型检查功能,因此每一个变量都有固定的数
据类型。
let msg: string = ‘hello world’
let: 声明变量的关键字,const则代表常量
msg: 变量名,自定义
string: 变量的数据类型

常见类型

// string: 字符串,可以用单引号或双引号
let msg: string = 'hello world'
// number: 数值,整数、浮点数都可以
let age: number = 21
// boolean:布尔
let finished: boolean = true
// any: 不确定类型,可以是任意类型
let a:any = 'jack!
a= 21
// union; 联合类型,可以是多个指定类型中的一种
let u: string|number|boolean = 'rose'
u = 18
// Object:对象
let p = {name: 'Jack', age: 21}
console.log(p.name)
console.log(p['name'])
// Array: 数组,元素可以是任意其它类型
let names: Array<string> = ['Jack','Rose']
let ages: number[] = [2118]
console.log(names[0])

条件控制

TypeScript与大多数开发语言类似,支持基于if-else和switch的条件控制。

if-else:

//定义数字
let num:number = 21
// 判断是否是偶数
if(num % 2 === 0){
	console.log(num +' 是偶数')
}else{
	console.log(num +' 是奇数')
}
// 判断是否是正数
if(num > 0) [
	console.log(num+' 是正数')
else if(num < 0){
	console.log(num+' 是负数')
}else {
console.log(num+' 为0')
}

注意: 在TypeScript中,空字符串、数字0、null、undefined都被认为是false,其它值则为true
switch-case:

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等提供了快捷迭代语法。

// 普通for
for(let i = 1; i <= 10; i++){
	console.log('点赞'+i+'次')
}
// while
let i = 1;
while(i <= 10){
	console.log('点赞'+i+'次')
	i++;
}
//定义数组
let names: string[] = ['Jack','Rose']
// for in 送代器,遍历得到数组角标
for (const i in names) {
	console.log(i ++ names[i])
}
// for of 送代器,直接得到元素
for (const name of names) {
	console.log(name)
}

函数

TypeScript通常利用function关键字声明函数,并且支持可选参数、默认参数、箭头函数等特殊语法。

//无返回值函数,返回值void可以省略
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)

// 箭头函数
let sayHi = (name: string) =>{
	console.log('你好,' + name +'!')
}
sayHi(' Rose')

// 可选参数,在参数名后加 ?,表示该参数是可选的
function sayHello(name?: string){
	// 判断name是否有值,如果无值则给一个默认值
	name = name ? name :'陌生人'
	console.log('你好,' + name +'!')
}
sayHello('Jack')
sayHello()

// 参数默认值,在参数后面赋值,表示参数默认值
// 如果调用者没有传参,则使用默认值
function sayHello(name: string = '陌生人'){
	console.log('你好,' + name +'!')
}
sayHello('Jack')
sayHello()

类和接口

TypeScript具备面向对象编程的基本语法,例如interface、class、enum等。也具备封装
继承、多态等面向对象基本特征。

//定义教举
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($r( 'app.media,mate60' ))  //访问的是entry.src.main.resources.base.media			文件夹内的图片,app.为固定格式,可以省略文件后缀名png
			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('https://img-home.csdnimg.cn/images/20230825101811.png').width(250) // 可以用百分比,也可以用数字(默认带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<Person> = [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
struct Index {
  @State p:Person = new Person('Jack',21,new Person('萧寂',25))
  build() {
    Row() { 
      Text(`姓名: ${this.p.gf.name},年龄: ${this.p.gf.age}`)
        .onClick(()=>{
          this.p.gf.age+=1  // 发现并不能增加,因为嵌套类型以及数组中的对象属性无法触发视图更新,后面会讲到解决方法
        })
    }
  }
}

ArkUI的状态管理

1.@State装饰器

在声明式UI中,是以状态驱动视图更新

状态(State): 指驱动视图更新的数据(被装饰器标记的变量)
视图 (View):基于UI描述渲染得到用户界面

@State装饰器标记的变量必须初始化,不能为空值
@State支持Object、class、string、number、boolean、enum类型以及这些类型的数组
嵌套类型以及数组中的对象属性无法触发视图更新
这个装饰器前面讲过,这里简单描述即可

2.@Prop和@Link

3.@Provide和@Consume

4.@Observed和ObjectLink

ArkUI页面路由

ArkUi的属性动画和显式动画

组件转场动画

小案例实现摇杆功能

文章来源:https://blog.csdn.net/weixin_68658847/article/details/135059262
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。