ArkTs进阶

arkts进阶,进一步详解字符串、数组、运算符、分支结构、循环结构、常见事件方法、状态管理、装饰器、泛型定义以及模块化方法

字符串

加号两边只要有字符串,就是拼接的作用。

模版字符串(xxx)主要用于拼接多个变量的字符串拼接

let name: string = 'Tom'
console.log(`姓名:${name}`)

类型转换

1.字符串转数字
Number():字符串 直接转数字,转换失败返回NaN(字符串中包含非数字)(常用)
parseInt():去掉小数部分 转数字(取整),转换失败返回NaN
parseFloat():保留小数部分转数字,转换失败返回NaN (用得少)
需要是计算,必须加号都是数字 -> 字符串类型,转成数字

2.数字转字符串
数据.toString() 原样转字符串
数据.toFixed(保留几位小数) 四舍五入(多用来展示几位小数)


运算符

算数运算符:+ - * / %
赋值运算符:+=、-=、*=、/=、%=
一元运算符:++ --
比较运算符:> >= < <= == != ===(严格相等,只有数值和类型都相等,结果才会为true)
逻辑运算符:&&、||、! (与或非)

运算符优先级(由高到低):小括号、一元(++,--,!)、算数、比较(>,>=,<,<=)、比较(==,!=)、逻辑运算符(先&&后||)、赋值


数组

let names:string[] = ['aa','bb','cc']

添加元素:

① 往开头新增:unshift(新增的值) 返回操作后的数组长度

② 往结尾新增 push(新增的值) 返回操作后的数组长度

删除元素:

① 从开头删除 shift,返回删除的项

② 从结尾删 pop,返回删除的项

记:开头(S),结尾(p)

任意位置添加/删除数组元素(splice)

语法:数组名.splice(操作的起始位置,删除的个数,新增元素1,新增元素2,...)

from方法用于生成测试数组,可选长度,里面没有内容。

Array.from({ length: 10 })

对象数组:

1.约定接口(对象的类型)

interface Student {
  stuId: number
  name: string
  gender: string
  age: number
}

2.基于接口创建对象数组

let stuArr: Student[] = [
  {stuId: 1, name:'小丽', gender: '女', age: 12},
  {stuId: 2, name:'小红', gender: '女', age: 13},
  {stuId: 3, name:'小明', gender: '男', age: 13},
  {stuId: 4, name:'小刚', gender: '男', age: 12},
  {stuId: 5, name:'小强', gender: '男', age: 13},
]

3.使用(通过下标访问)

console.log('小红:', stuArr[1].name)
console.log('小红:', JSON.stringify(stuArr[1]))

同样支持for...of,普通for进行遍历

注:
包括对象的复杂数据,如果想要在日志中打印,需要调用一个方法,转成字符串
JSON.stringify(复杂类型) —— 对象/数组
对象数组的情况需要更新,需要修改替换整个对象。(不可直接修改对象数组中的某一个属性值,否则不会变!!!)

剩余参数(展开运算符)
可以将 函数 或 方法 中一个不定数量的参数表示为一个数组
语法:...数组名:数组类型

function sum (n1: number, n2: number, ...argsArr: number[]){
  console.log('剩余数组', argsArr)
  //如果有剩余的参数,就继续使用剩余参数。若没有剩余参数即只使用前面的参数

注:展开运算符只能用在数组上


分支结构

三种语句执行结构:顺序结构、分支结构、循环结构

1.单分支(满足条件,就会执行一段代码)
2.双分支(满足条件,会执行A代码,不满足,执行B代码)
3.多分支:可以解决多种分支的情况
4.switch分支

一般用于精确匹配,不同的值执行不同代码

let fruit: string = '苹果'
switch (fruit){
  case '苹果':
    console.log('苹果价格:2.8元一斤')
    break  //注意:break不可漏,否则会继续执行下一条case
  case '香蕉':
    console.log('香蕉价格:5.5元一斤')
    break
  default:
    console.log('提示:该水果不存在')
}

5.三元表达式
语法:条件?条件成立执行的表达式:条件不成立执行的表达式

注:除了switch,其余条件控制亦可控制UI界面的显示


循环结构

while循环:

 let num:number = 1
 while (num <= 100){
   console.log('打印:',num)
   num++
}

for循环:

for(初始值;循环条件;变化量)  
 {  
   重复执行的代码(循环体)  
 }

for of 循环:

语法:for(let item of 数组名) {}
for...of: 在...之中,进行循环
item: 声明的一个变量,用来在循环的时候接受 每一个数组元素

ForEach 渲染控制

语法:ForEach(arr,(item,index) => {})
ForEach 可以基于数组的个数,渲染组件的个数(简化代码)
item是需要遍历的每一项,index是下标

break和continue:

break:终止整个循环(后面的循环不执行了)
continue:退出当前一次循环的执行,继续执行下一次循环


常见事件方法

1.onclick

语法:onClick( (参数) => { 事件内容 } )

2.对话框 alertDialog

AlertDialog.show({
  message: 'xxx'
 })

3.Math方法

求随机数:Math.random ([0,1)的小数)
向下取整:Math.floor


状态管理

如果希望构建一个动态的、有交互的界面,就需要引入“状态”概念
点击交互出发了文本状态变更,状态变更 引起了 UI渲染

普通变量,只能在 初始化 时渲染,后续变化了,也不会引起更新。
状态变量,被装饰器修饰,值的改变,会[自动]引起 界面的更新

注意:
组件外变量不需要this,即可访问。而组件内变量必须用this.xxx访问。
组件内的普通变量,不能加修饰前缀,如let。
组件内状态变量需加上@State装饰器修饰!
状态变量中必须加上数据类型,不然会报错!

@State

注意:不是状态变量的所有更改都会引起刷新。只有可以被框架观察到的修改才会引起UI刷新。
1.boolean、string、number类型时,可以观察到数值的变化
2.class或者Object时,可观察 自身的赋值 的变化,第一层属性赋值的变化,即Object.keys(observedObjecct)返回的属性。见第三条。
3.复杂类型:class或者Object时,第一层随便改,嵌套需要进行整个嵌套的对象替换

@prop

装饰的变量可以和父组件建立单向的同步关系
@Prop 装饰的变量是可变的,但是变化不会同步回其父组件
子组件,可以修改到prop传值,但修改的更新不会同步到父组件。通常不会直修改 prop 传值,父组件的状态一旦变化,会自动向下同步,修改就被覆盖了。

this指向问题:

若在子组件中希望父组件同步更新,需要调用父组件传递过来的方法。
父组件必须使用箭头函数
如果父组件没有用箭头函数,意味着this指向子组件。
在普通函数内部,this通常指的是当前执行上下文的对象。
箭头函数没有自己的this绑定,它会从外围作用域继承this值
使用箭头函数的好处,可以使用外部环境的this,不受传递过去后的执行环境影响
通常为了实现双向同步,一般不会使用此方法,直接使用@Link装饰器即可

@Link

使用@Link 可以实现父组件和子组件的 双向同步
使用步骤:
1.将父组件的状态属性 传递给子组件
2.子组件通过 @Link修饰 即可

注:子组件中Link声明的变量不可以赋值!

@Provide和@Consume

将数据传递给后代,和后代的数据进行 双向同步 (跨层级双向同步)
步骤:
1.将父组件的状态属性使用@Provide修饰
2.子组件通过@Consume修饰

注:
子组件变量名必须和父组件统一!
子组件中Consume声明的变量不可以赋值!
使用Provide和Consume时,在父组件调用子组件时,无需在子组件括号内写传入的参数对象,而是要保证父子变量名统一即可实现传递。


装饰器

@Extend 样式重用

可以扩展 特定组件 的 样式、事件,实现 复用 效果

//头部定义
@Extend(组件名)
function 函数名(参数1,参数2){} //可传递参数

可在容器中对应的组件使用函数名调用定义的样式。

@Styles 通用样式

抽取通用属性、事件(只能抽取通用的样式

//开头定义
@Styles function commonStyles() {
  .width(100)
  .height(100)
  //注意:组件内定义的元素,全局不可读
}

注:
styles修饰的不支持传参
组件内Styles修饰的方法名前不可加function

@Component 自定义组件

概念:由框架直接提供的称为 系统组件,由开发者定义的称为 自定义组件
系统组件:如Row、Text......
自定义组件可以使大的页面,拆分成很多小的部分

@Component
struct MyHeader{
  
}

1.通用样式事件

自定义组件可以通过点语法,设置 通用样式,通用事件

注:给组件设置属性是给外层添加的,而不是内部根组件(如Row)添加的。且内部事件的优先级高于外部事件

2.成员函数变量

除了必须要实现build()函数外,还可以定义其他的成员函数,以及成员变量

@Component
  struct MyPannel {
    //成员变量 - 数据 —— 可外部传入覆盖
    @State title: string = '默认的大标题'
    //成员变量 - 函数 —— 可以外部传入覆盖
    getMore = () => {
      AlertDialog.show({
        message: '查看更多'
      })
    }
    //成员函数 —— 不可以外部传入覆盖
    sayHi(){
      AlertDialog.show({
        message: '打招呼,你好!'
      })
    }
    build(){}
  }

注意:在使用自定义组件时,在括号内可以传入参数,覆盖自定义的变量,但是不能对函数进行覆盖,只能对函数变量进行覆盖。

MyPannel({
  title: '小米有品众筹',
  getMore(){
    AlertDialog.show({
      message: '查看7款众筹'
    })
  }
})

@Builder 轻量级封装

自定义构建函数(结构、样式、事件)

注意:
1.builder只能使用组件内的状态
2.可传递参数

@Builder
  function navItem(icon: ResourceStr, txt: string) {
    Column({ space: 10 }) {
      Image(icon)
      Text(txt)
    }
  }

全局定义调用时直接使用方法名调用,在组件内定义时,必须用this.方法名调用。

@BuilderParam 传递UI

利用 @BuilderParam 构建函数,可以让自定义组件 允许外部传递UI

1.定义构建函数
定义 BuilderParam 接收外部传入的UI,并设置默认值

@Component
struct SonCom{  
//在自定义组件内使用
@BuilderParam ContentBuilder: () => void = this.defaultBuilder
//必须要写默认的Builder进行初始化
@Builder
  defaultBuilder() {
    Text('默认的内容')
  }
  build(){
    //2.使用构建函数,构建结构
    Column(){
      this.ContentBuilder()
    }
  }
}

2.使用此自定义组件,并且传入UI结构

Column(){
  SonCom() { //若没有花括号,则表示不传结构,那么使用的就是上面默认的结构
    //直接传进来(尾随闭包)
    Button('传入的结构')
  }
}

3.多个 BuilderParam 构建函数
子组件有多个BuilderParam,必须通过参数的方式来传入
即多个结构UI需要定制的场景使用

@BuilderParam tBuilder: () => void = this.tDefaultBuilder
@BuilderParam cBuilder: () => void = this.cDefaultBuilder
@Builder tDefaultBuilder() {
  Text('我是默认大标题')
}
@Builder cDefaultBuilder() {
  Text('我是默认内容')
}

使用时,传入多个BuilderParam时,不可再使用尾随闭包,必须通过参数传入!

@Builder ftBuilder(){}
@Builder fcBuilder(){}
MyCard({ //若有多个结构UI,要通过参数的方式传入,不能通过尾随闭包传递!
  tBuilder: this.ftBuilder,
  cBuilder: this.fcBuilder
})

泛型(广泛的类型)

泛型可以让 函数 等,与多种 不同的类型 一起工作,灵活可复用
简单说:类型可变(类型可当做参数传递)

function 函数名<Type>(形参:Type): 返回值类型{
      return 形参
 }

调用时,使用:函数名<Type>(实参)

注:调用时类型名最好加上,方便知道传入的是什么类型
如下注意区分:

function test<T>(arr: T[]): number{} //这里T是表示传入的是数组,但是什么类型的数组不一定。
test<number>([1,2,3]) //调用时候,<>中的要填写number,表示T是number型数组
function test2<T>(arr: T): number{}//这里T是表示传入的可以是任何类型,不一定是数组。
test2<number>(3) //这里T可以是number类型
test2<number[3]>([1,2,3]) //这里T也可以是number型数组

约束泛型:

给传递的类型参数,添加限制(泛型约束)

interface ILength {
  length: number
}
function fn<T extends ILength>(param: T){ //传入的类型必须要有 接口中的属性
  console.log('',param.length)
}
fn<string>('abc') //这里字符串类型有length属性,可以传入

多个泛型变量

可以传递多个类型参数。

泛型接口

定义接口的时候,结合泛型定义,就是泛型接口

//定义接口
interface IdFunc<T>{
  //约定有两个方法(id类型不定,可能是string或number)
  //1. 传入 id 值, 就返回 id 值
  //2. 返回一个 ids 数组
  id: (value: T) => T //类型都可以用T
  ids: () => T[]
}
//实现接口
let obj: IdFunc<number> = {
  id(value: number){
    return value
  },
  ids() {
    return [1,2,3]
  }
}

泛型类

//定义类的时候,配合泛型一起定义
class Person<T> {
  id: T
  constructor(id: T) {
    this.id = id
  }
  getId (): T {
    return this.id
  }
}
let p: Person<number> = new Person<number>(10)
console.log(p.getId().toString())

模块化

模块化:把一个大的程序,拆分 成若干个小的模块,通过 特定的语法, 可以进行任意组合
ArkTS中,每个ets文件,都可以看做是一个模块

导入和导出

默认导出导入
默认导出:指一个模块,只能默认导出 一个值 或 对象。使用时,可以自定义导入名称。

1.默认导入
路径:查找文件时,从起点到终点的路线
相对路径:从当前文件出发查找目标文件

export default xxx
import xxx from 'xxx'

2.按需导入
按需导出:指一个模块,可以按照需要,导出多个特性
按需导入的名称必须和导出的名称一致,花括号中名称顺序可以不固定。(若希望换名字,则需要使用as引用别名)

//导出
export let price: number = 1
export let price2: number = 2
//导入
import {price,price2} from 'xxx'

3.全部导入
将所有的按需导入,全部导入进来 ,导出部分不需要调整,调整导入的语法即可

import * as module from xxx '../xx'  //‘*’不能当变量用,必须as一个别名

注:导出时可以一次性导出多个特性

export {name1,name2,name3}

TAG:none

发表新评论