【小白学鸿蒙-学习笔记】关于鸿蒙的一点吐槽与近期学习的体会

本文是作者学习鸿蒙OS的过程记录,包括遇到的问题与吐槽,如设备适配、版本混乱和文档易用性。此外,文章还总结了ArkTS语法和HarmonyOS组件学习的重点,如类型、接口、类、函数、泛型以及组件的使用,如Flex、Column和Tab等。

前言

学习HarmonyOS也有一段时间了,发现了一些问题,也有一些体会,写在这里, 也是对自己近期的一个学习体会的总结。因为我之前是学Java的,没有安卓的相关开发经验,只有玩过一段时间的微信小程序,所以以下内容,如有错误,敬请指正。

吐槽

  1. 学习HarmonyOS最大的一个问题就是目前手头上没有合适的华为手机,借了一个Nova5Pro,结果当时不能升级到3.0系统,后面升级到了3.0系统之后,API版本还是6,导致一直都没有真机做测试,使用模拟器和预览器也勉强够用,不过学习过程中也有遇到一些Bug,后面再说

  2. 第二个问题就是HarmonyOS的版本跟API的版本,个人感觉有点混乱,因为你手上拿着一个设备,你是完全不知道它支持的API版本是多少,此处强烈建议华为的人想办法解决一下这个问题,有一个最简单的方式就是直接把API版本写在手机的开发者模式,这样进去就知道当前手机的API版本,这样不是比较简单吗?

  3. 感觉官方文档对于初学者来说并不是很友好,学习路线并不线性,官方文档表示,后期鸿蒙开发的主力肯定是ArkaTS+Storg模型,所以我选择直接先从API8入手,学习ArkTS,但是发现,对于ArkTS的学习,我个人之前只学过JS,对于TS的语法很多时候看到的时候一脸懵逼,但是官方文档对于这块内容好像默认你都会似的,也没写,只能自己去查,去摸索,增加了我的学习成本。

  4. CodeLabs的形式非常好,有用的内容也不少,但是一开始,我随便打开一个CodeLabs也是一脸懵逼的,为什么这么多文件,为什么这么多引用,对于初学者而言,不是应该简单点好理解一些比较好吗,但是CodeLabs目前的形式,个人感觉有点吓到我,并且对于CodeLabs的引导,给我一种,“我们来学习,这是1,这是2,这是3,1+1=2,1+2=3,你学会了吗?好了现在我们来造航母吧!”我个人感觉非常难受。不知道其他人会不会跟我有同样感觉。

吐槽就先吐槽到这里,接下来对目前学习的一个内容进行一个总结。

知识总结

对于这块内容,我是站在一个新手的角度得出的内容,如有不对的内容,请指正

入门:

基础:

了解:

熟悉:

重要

TS通用语法

类型

变量声明

name:type =  value
复制

联合类型

  • 打个比方说image的src属性,传进去的参数可以是字符串也可以传一个资源路径,为什么可以这样呢?点进去看一下,他是这么写的:
src: string | PixelMap | Resource
复制
  • 在类型定义的时候,是用了"|",意思是可以是这个类型,也可以是另一个类型

数组类型

  • 最基础的很简单:
let numberArray: number[] = [1, 2, 3] // var numberArray = [1, 2, 3];
let numberArray1: Array<number> = [4, 5, 6] // var numberArray1 = [4, 5, 6];
复制
  • 联合类型也可以用数组:
let arr: (string | number)[] = [1, 'a']
复制
  • 复杂对象也可以用数组:
let arr: {name: string, age: number}[] = [
  {name: 'Jane', age: 17},
  {name: 'Jian', age: 20}
]
复制

元组

  • 元组算是一个新东西,Python也有用到,本质上就是一个确定数量和类型的数组

  • 类型和位置需要一一对应

let data: [number, string, boolean] = [2, '3', true] // var data = [2, '3', true];
复制

枚举

  • 这个也是使用enum枚举关键字,可以为枚举项赋值,不赋值默认从0开始,赋值后,这个值就是该枚举中枚举项的下标
enum Direction {
    Up = 1, // 不赋值默认从0开始
    Down,
    Left,
    Right
}

console.log(Direction.Down) // 2
console.log(Direction[1]) // Up
复制

类型断言

  • 逻辑类似于Java的类型强转,有两种实现方式
str as string

<string>str   //这两种方式都是将变量str,强制变成string类型
复制

类型别名

  • 使用type关键字可以给某一个Object对象起一个临时性的别名
type Lady = {name: string, age: number} // 对象类型可以使用类型别名
let arr: Lady[] = [
  {name: 'Jane', age: 17},
  {name: 'Jian', age: 20}
]
复制

接口

接口提供一种数据结构的抽象定义,跟Java的会有所区别,不仅有方法的定义也有属性的定义,定义完了他就是一种数据结构

interface MyInterface {
name: string,
age: number,

say(): string
}

function fn(opts: MyInterface) {
//...
}

fn({
name:"张三",
age:18,
say(){
 return "哈哈哈"
}
})
复制

接口的实现与继承

  • 跟Java一样,类使用implement关键字实现接口,实现接口后需要实现接口中的方法
  • 可以实现多个接口
  • 接口之间可以继承,A接口可以继承B接口和C接口,使用Extends关键字

属性声明

  • 跟Java有所区别,属性默认是Public的
  • Public在所有地方都可以访问
  • protectd受保护,在类内部和其子类中能够访问,实例中不能访问
  • private:私有,只能在内部访问。
  • readonly:只读,实例不能对这个属性赋值

构造函数关键字

  • 在类中,使用constructor关键字声明构造函数

静态成员

  • 跟Java一样,使用Static关键字修饰,修饰后无法使用this访问,必须使用类名调用和修改

存取器

  • 使用get\set修饰属性的同名函数,给私有属性一个存取方式,在存的时候可以设定一定的规则,不符合规则的不存

抽象类

  • 跟Java一样,抽象类不能用来创建对象,只是专门用来被继承的
  • 抽象类中可以有抽象方法和实例方法,抽象方法必须被子类实现,实例方法子类的实例对象可以直接调用

函数

函数类型

  • 在TS中,函数有两种类型,一种是函数声明,其实就是先定义函数,然后用到的时候,使用函数名调用

  • 另一种类似于Java的匿名函数,用到的时候直接使用function关键字创建一个函数

  • 函数的返回值跟属性的返回值一样,需要使用“:返回类型”

//函数声明
function sum(x: number, y: string): string {
  return x + y
}

//函数表达式 这种情况,sum的类型是ts自动推断得出的string类型
let sum = function (x: number, y: string): string {
  return x + y
}
复制
  • 函数也可以成为属性的一种类型
let sum:(x:number,y:string)=>string
//属性sum为一个函数,函数形参为(x:number,y:string),返回值为string
复制
  • 函数表达式也可以简化成为箭头函数
(形参)=>{
    运算逻辑
}
复制

可选参数

  • 当在组件或者函数中,某些参数可传可不传,就可以用到可选参数,使用方式如下,

  • 注意,如果一个函数中同时有必选参数和可选参数,可选参数一定要在后面

add(num?:number){
    
}
复制

默认参数

  • 当使用上面的写法的时候,num是没有默认值的,如果我们在函数内有用到该参数,这样就可能会报错,这个时候可以使用默认值的方式,这样参数也是可以省略的,如果省略就会使用默认值
add(num:number=3){
    
}
复制

剩余参数

  • 在Java中,这个叫可变参数,在指定函数的参数个数时,可能无法确定,那么可以将最后一个参数封装成为一个集合,然后在集合中遍历取出参数
function sum(x: number, ...rest: string[]): string[] {
  return rest.map(i => i + x)
}
复制

函数重载

  • 在Java中也是有方法重载,同名的方法,根据传参的内容不同调用不同的方法,但是在Ts中,函数的每一个形参可以指定不同的参数类型,那么可以在函数内部进行参数判定,但是这种会比较麻烦,所以能用重载也可以用重载
function fn(x: number, y: number): number
function fn(x: string, y: string): string
function fn(x: string|number, y: string|number): string|number{
  if(typeof x === 'number' && typeof y === 'number') {
    return x + y
  } else if(typeof x === 'string' && typeof y === 'string') {
    return x + '_' + y
  } else {
    return '错误'
  }
}

// 如果没有前两个重载这里不会报错,输出内容是“错误”
// 如果有了前两个重载这里就会报错,因为此时的参数不符合重载函数的任何一种传参数据类型
fn(10, 'kkk')
复制

泛型

泛型函数

  • 泛型函数跟Java一样,可以让函数的参数类型在使用时决定。

泛型接口

  • 泛型接口跟泛型函数差不多

泛型类

  • 其实跟Java也差不多

TS中的This

  • 如果在箭头函数中,this指向的是当前组件,
  • 但是在如果使用匿名函数的方式,需要在事件后.bind(this)

ArkTS语法

UI描述

UI组件

  • 无参数构造组件

  • 有参数构造组件

组件名(参数){
    子组件
}
复制

属性方法

  • 通过链式调用的方式
  • 参数可以传正常的参数外,可以使用枚举类型,具体的可以按进去,看需要传入什么参数

事件方法

  • 为当前组件绑定事件,当事件发生时可以进行响应
  • 使用方式有三种,一般建议使用前两种
  • 直接写箭头函数,
  • 把函数定义在外面,然后通过This.functionName调用(不用加括号)
  • 使用匿名函数,但是当函数体里面用到this关键字时,需要.bind(this),这个this指向当前组件

子组件配置

  • 当一个组件可以包含子组件时,子组件需要写在{ }里面
  • 子组件也可以嵌套其他的子组件

装饰器

带@ 就是装饰器,如@State、@Entry

组件定义装饰器

@Component

  • 简单理解,被修饰后,这就是一个组件了,可以复用
  • 如果想给其他页面复用,需要使用export关键字,然后对应页面使用 import关键字即可导入使用

@Entry

  • 如果你想让一个组件单独以一个页面展示,那就需要用到这个修饰器,没什么好说的
  • 切记:是一个页面一个,我当时傻傻的以为入口嘛应该就一个,三个页面就index页面加了这个,结果毫无疑问的报错了

@Rreview

  • 学会用预览器之后就会发现,使用预览器还是挺爽的,但是预览器只能预览页面,也就是有加@Entry的组件,如果我想预览自定义组件怎么办呢?这就需要用到@Preview了,给自定义组件加上这个,就可以以组件的形式去预览了,所见即所得,还是挺爽的。

动态构建装饰器

@Builder

  • 这个装饰器可以修饰一个函数,函数内部定义一个组件,可以达到复用的目的
  • 在定义动态组件的时候,可以声明一些参数,然后在组件内部使用它,这样当动态组件被使用的时候,可以传参进去,就达到动态复用的目的

@Styles

  • 这个装饰器是用来降低重复的样式代码,不过它里面只能声明一些通用属性,不能声明组件特有的样式。
  • 并且两种使用方式:要么就在builder函数之前,要么就在当前组件之外,这样要加一个Function关键字

@Extend

  • 如果你需要用到很多个Text组件,然后又不得不为他们定义相同的样式的时候,可以试试@Extend关键字,它可以给基础组件快速扩展同一类样式。
  • 这个装饰器只能声明在当前组件的外面,并且也要Function关键字

@CustonDialog

  • 使用这个注解可以让你声明一个弹出框,并在想要的时候展示他
  • 步骤大概是,
  • 创建一个弹窗组件
  • 然后在父组件中创建对应的控制器,然后在控制器的构造函数中传入此弹窗组件及其他参数
  • 为当前页面的某一个组件绑定事件,当事件触发时,执行弹窗控制器的open方法
  • 具体的使用方式参照可以点击这里

状态管理装饰器

@State

  • 这个装饰器用来修饰组件内部的变量,当该变量发生变化时,页面上应用该变量的内容会重新刷新
  • 这个只是单向绑定,修改值时并不会自动修改变量,所以需要绑定事件,在事件里修改变量,比如当这个值绑定一个输入框的时候,输入框中值的变化不会同步到该变量上,需要手动去修改
  • 在声明时要给定初始值

@Prop

  • 这个装饰器修饰的变量声明在子组件中,但是初始化由父组件完成,父组件创建该子组件时,需要使用父组件的@State变量去初始化它
  • 也可以理解为父组件的@State变量绑定到了子组件的@Prop变量上,当父组件的@State变量发生变化时,使用到该@Prop变量的组件也会发生变化,但是反过来就不会
  • 简单来说就是声明一个需要父组件传递过来的变量,谁用到我这个组件,谁就要给我传这个变量

@Link

  • 这个装饰器算是增强版的@Prop,因为它可以让父组件中的@State变量跟子组件中@Link修饰的变量联动起来,当任一一方对变量进行修改时,会同步到另一方。

  • 值类型必须相同,不能在组件内部初始化,必须接收父组件的@State变量初始化

  • 使用时需要使用$关键字,

子组件变量:$父组件变量
如text:$text
复制

@Watch

  • 这个装饰器用来监视某一个状态变量的变化,当发生变化时,就会调用该装饰器注册的函数

  • 使用方式为:

// @State @Watch("函数名")  变量名:变量类型= 初始值

@State @Watch("add") num:number = 0
//当num每一次发生变化时,就执行一次Add函数
add(){
    this.xxx+=1
}
复制

@Consume和@Provide

  • @Provide为数据的提供方,可以讲数据同步给其他被@Consume修饰的变量,但是前提是,变量名需要一样

  • @Consume为数据的接收方,本身不可以自行初始化变量,当感知到@Provide数据的更新时,会触发当前组件的重新渲染。

  • 在使用@Provide和@Consume时,要避免循环引用导致死循环。

渲染控制

if/else

  • 这是很好理解的吧,为true就渲染该组件,为False就执行Else里面的组件

ForEach

  • 这个也很好理解,特别适合于那种样式一样只有内容不一样的组件内容填充
  • 使用需要三个东西,遍历的集合,渲染子组件的方法,生成Key值的方法

LazyForEach

  • 数据懒加载,使用这个它不会一下子把所有的加载出来,而是按需加载和创建

组件

容器组件

Flex

  • 弹性盒容器组件,默认是水平的主轴,跟垂直的交叉轴,也就是说是横向排列的
  • 可以设定FlexDirection,改变主轴的方向,变为列排列之类的等等
  • 也可以设定justifyContent,是主轴的对齐方式方式
  • 也可以设定AlignItems,设定交叉轴的对齐方式
  • 具体的可以看文档

Row

  • 行组件,容器内元素以行排列,也没啥好说的
  • 列默认的宽度是100%,横向占满一行
  • RowSplit:每个子组件加一道分割线

Column

  • 列组件,容器内元素以列排列,更没啥好说的
  • 列默认的高度是100%,纵向占满一列
  • ColumnSplit :每个子组件之间加一道分割线

List

  • 列表组件,常用于搭配ForEach实现统一类型元素的渲染
  • 内含ListItem

Tabs

  • 导航组件,内含TabContent作为页签,每一个页签对应着一个内容视图

Navigator

  • 路由容器组件,常用来套在某一个元素外面,为这个元素添加一个跳转效果,当该元素被点击时就执行跳转

Stack

  • 堆叠容器,就是栈的排列方式,先放进去的在最底下,然后一层一层铺上去

RelativeContainer

  • 相对布局组件,但是从API9才开始支持,API8不能用
  • 可以设置容器内组件相对于其他容器,或者相对于父容器的位置,相对来说比较自由,但是也比较繁琐的一个布局

Swiper

  • 滑动轮播组件,可以滑动,也可以轮播

GirdRow

  • 栅格容器组件,搭配GridCol使用,
  • 可以理解为把屏幕按比例分成若干个栅格,布局按栅格划分,在不同的屏幕尺寸上,栅格大小是不同的,所以占用屏幕尺寸也是会等比例缩小或者放大,从而实现屏幕大小的自适应

Grid

  • 网格容器,由行和列分割的单元格组成,由GridItem占用格的大小,来展现布局

Panel

  • 可以理解为一种可滑动的弹出框,可以用作应用内通知栏

Scroll

  • 可以滚动的容器组件,当子组件布局尺寸超过父组件时,可以滚动

SideBarContariner

  • 侧边栏组件,传入的第一个组件为侧边栏,就是展开的时候会显示出来的东西,第二个组件是主页面组件

Refresh

  • 下拉刷新动效,具体可以看文档

Badge

  • 标识组件,就是类似于微信的未读提醒

Counter

  • 计数器组件,在值的两侧有一个加减符号,可以分别设定回调函数,以实现加减功能
  • 可以加一个input组件,实现可以加减,也可以输入的功能
  • 目前有个Bug,当含有子组件时,设置子组件的margin属性,此时子组件就消失了

AlphabetIndexer

  • 字母索引条,一般用在通讯录应用啥的,

基础组件

Button

  • 按钮组件,具体看文档

Image

  • 图片组件,具体看文档

Text

  • 文本组件,具体看文档
  • 可以添加Span组件,用于给文本做一定装饰

TextInput

  • 文本输入框组件,具体看文档

Blank

  • 这个组件一定程度可以让我们的布局设计更简单,因为它是默认占据剩余的空白空间
  • 仅当父组件为Row/Column时生效,当父组件不设置宽度时,Blank失效,所以可以设置个最小宽度

Divder

  • 分割器组件

LoadingProgress

  • 加载动效的组件,具体看文档

Radio

  • 单选框组件,没啥说的,看文档

CheckBoxCheckboxGroup

  • 多选框组件,与全选,看文档
  • 有一点需要特别注意,当有用到CheckboxGroup时,该组件必须在最上面

Toogle

  • 勾选框样式、状态按钮样式、开关样式
  • 在使用时需要指定样式与默认状态

DataPanel

  • 数据面板组件,有线形跟环形两种样式,用于体现数据占比

滑动选择器

  • DatePicker:日期选择器
  • TextPicker:文本选择器
  • TimePicker:时间选择器
  • 这些选择器可以搭配Panel组件或者弹窗组件来进行弹出选择

Marquee

  • 跑马灯组件,当文本内容宽度超出组件宽度时,实现跑马灯样式的滚动效果

Navigation

  • 页面的根组件,可以用来设置页面的标题、工具栏、菜单等内容

TextClock

  • 将当前时间以文本形式展示

TextTimer

  • 文本计时器组件,可以正计时,倒计时、
  • 控制器可以开始、暂停、重置

下拉选择菜单

  • Select:给定一个数组,返回选择的数组下标

评分条

  • Rating:可用于电影评分之类的场景

滑动条

  • Slider:可用于滑动调节值

进度条

  • Progress:各种样式的进度条组件

二维码

  • QRCode:可以将Value转化成二维码图片进行展示

搜索框

分割器

  • Divider:提供一个分割条的样式,仅此而已

图表

  • Gauge:构建 一个环形图表,然后有一个指针指向当前数据所在的位置,可以理解为汽车上的速度指示器那种样式

媒体组件

Video

  • 视频播放组件,这个需要用到的时候,再去看吧

弹窗

警告弹窗:AlertDialog

  • 其他的弹窗也都差不多,可以看文档

资源的使用

  • 在开发过程中,肯定需要用到很多的资源,比如定义好的字符串、图片音频等,这些资源文件统一放在Resources目录下
  • 使用方式1:$r("app.type.name") 此方式可以调用base目录下的资源,切记,此方式下,不支持字符串拼接
  • 使用方式2:$rawfile("filename") 此方式直接使用rawfile目录下的文件(一般使用的是图片文件),并且需要包含文件后缀,此方式可以进行字符串拼接
  • 其他可以看文档

测验

完成以上内容的学习时,可以尝试完成测试

功能模块:

@ohos.router (页面路由)

  • router.push:跳转到指定页面
  • router.replace:使用页面替换当前页面,当前页面会被销毁
  • router.back:返回到上一页,或返回到指定页面
  • 可以传入一个参数:RouterOptions,该参数用于指定路由参数:跳转页面的url和传递的参数Params
  • router.getParams:在跳转后的页面中获取传入的参数,此参数为Object类型,需要使用router.getParams()['key']来获取对应的值

进阶

自定义组件的生命周期

aboutToAppear

  • 创建实例之后,build函数之前执行,可以在这里做一些数据的初始化操作

onPageShow

  • 仅对页面组件生效(也就是@Entry修饰的组件)
  • 每次显示时触发一次,可以做开屏定时器之类的操作

onBackPress

  • 仅对页面组件生效(也就是@Entry修饰的组件)
  • 用户点击手机上的返回按钮时触发,可以做一些提示性弹窗

onPageHide

  • 仅对页面组件生效(也就是@Entry修饰的组件)
  • 页面每隐藏时触发一次,暂没有合适的应用场景

aboutToDisappear

  • 当前组件的实例被销毁之前执行,比如当前页被路由replace时
  • 不能在这个时候修改状态变量
  • 可以执行一些释放资源的操作

基础能力

Timer (定时器)

  • setTimeout:延时执行一个函数,仅执行一次,返回延时器的ID
  • clearTimeout:传入上面的ID,可以关闭此延时器
  • setInterval:周期性执行一个函数,一直重复执行,直到被清除,返回ID
  • clearInterval:传入上面的ID,可以清除该周期性任务

参考资料:

HarmonyOS图标库

CodeLabs

示例代码

3.1API

3.0API

HarmonyOS开发指南

HarmonyOS第一课

华为开发者论坛

HCIA-HarmonyOS 应用开发工程师课程V2.0

HCIA-HarmonyOS应用开发工程师认证V2.0

 

进入华为专区,解锁更多内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值