鸿蒙开发ArkTs
1. 泛型
泛型在保证类型安全(不丢失类型信息)的同时,可以让函数等与多种不同的类型一起工作,灵活可复用
通俗一点就是:类型 是可变的!
-
泛型函数
Type 是泛型参数的名字,类似于之前的形参,可自行定义。
基本语法:
function 函数名称<T>(形参:T) {
let tmp:T = 形参
return [形参] // T[]
}
举例:
参考代码:
interface dog{
name:string
age:number
}
function idog<T>(asd:T){ //定义泛型
return [asd] //返回泛型数组
}
let qwe = idog<dog>({name:'大黄',age:3}) //定义qwe赋值为函数idog的返回值,idog的类型为接口dog
console.log(qwe[0].name,qwe[0].age)
-
泛型约束
上面说了泛型可以是任何类型,我们也可以对这个泛型进行限制。如果对泛型进行了类型限制,当输出不是限制的类型将会报错。关键词:extends
基本语法 : function 函数<Type extends 约束的类型>(){}
-
多个泛型参数
日常开发的时候,如果有需要可以添加多个 类型变量,只需要定义并使用 多个类型变量即可。同时多个类型都可以限制。如图:
-
泛型接口、类
泛型同样可以在定义接口和类时使用。
基本语法:
interface 接口<Type>{
// 内部使用Type
}
class 类名<Type>{
// 内部可以使用 Type
}
2. 递归
递归就是一个函数(方法),在其方法体中调用自己。(需要有退出条件!)
作用:可以用来做无限层级数据的处理和展示。
基本语法:
function func(){
func()
} //无限递归,没有退出条件(不可取)
演示案例:
参考代码:
interface iComment {
level: number //评论层级
avatar: string //头像
name: string //评论人
content: string //评论内容
childComment?: iComment // 子评论
}
@Entry
@Component
struct Index {
comment: iComment =
{
level: 0,
avatar: 'app.media.ic_avatar_113',
name: '软媒新友',
content: '鸿蒙PC版本操作系统赶紧上市',
childComment: {
level: 1,
avatar: 'app.media.ic_avatar_116',
name: '星河',
content: '赶紧上市,不然美国又来一次蓝屏',
childComment: {
level: 2,
avatar: 'app.media.ic_avatar_142',
name: '夜幕',
content: '点反对的,怕是不知道美国干的这事很少?'
}
}
}
@Builder lou(item:iComment){
Column() {
Row({ space: 10 }) {
Image($r(item.avatar))
.height(25)
Text(item.name)
.layoutWeight(1)
}
Text(item.content)
.width('100%')
}
.margin({left:10*item.level,top:10})
if (item.childComment){
this.lou(item.childComment)
}
}
build() {
Column(){
this.lou(this.comment)
}
.height('100%')
.width('100%')
}
}
3. 正则
正则表达式是用于匹配字符串中字符组合的模式(规则) ,常用于开发中的匹配、替换、提取。
-
元字符
| 边界符 | 说明 |
|---|---|
| ^ | 表示匹配行首的文本(以谁开始) |
| $ | 表示匹配行尾的文本(以谁结束) |
| 量词 | 说明 |
|---|---|
| * | 重复零次或更多次 |
| + | 重复一次或更多次 |
| ? | 重复零次或一次 |
| {n} | 重复 n 次 |
| {n,} | 重复 n 次或更多次 |
| {n,m} | 重复 n 到 m 次 |
正则表达式组合多种多样,深入研究的话极其耗费时间。建议了解即可,如果开发中需要用到了,建议问度娘🤪 跟我学习偷懒~
4. 数组常用 API
数组都是Array的实例化对象,鸿蒙开发中提供了很多的方法来供我们快速处理数据。常用的有:
| 方法名 | 作用 |
|---|---|
| indexof | 判断元素在数组中的索引,不存在返回-1 |
| join | 根据传入内容拼接数组,默认为,返回拼接结果,字符串 |
| forEach | 遍历数组,并且将数组的每一项作为参数传入到回调函数中,无返回值 |
| map | 基于原数组,创建一个新数组 |
| filter | 根据回调函数的执行结果,筛选出符合要求的元素,返回一个新数组 |
| find | 返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined |
| findIndex | 返回数组中满足条件第一个元素的索引。若没有找到则返回 -1。 |
| every | 返回数组中是否每一个元素都符合要求。 |
| some | 返回数组中是否有一个元素符合要求。 |
| sort | 方法的作用是对原数组的元素进行排序 |
| reduce | 数组求和 |
更多参考链接
-
数组常用API综合使用:
效果图:
参考代码:
import { branchFilter, heroList, Hero } from '../data/HeroData' //导入准备好的数据
@Entry
@Component
struct Index {
// 分路数组
branchList: string [] = branchFilter.split('|').map(item => item.trim()) //将分路中的字符串两边空格删除
// 选中的筛选条件
@State selectedIndex: number = 0
// 渲染用的数组
@State heroList: Hero[] = heroList //引用导入的英雄列表
// 当前时间
today: string = this.getTody()
// 排序条件
sortList: string[] = ['热度', '胜率', '登场率', 'Ban率']
@State isUpperSort: boolean = false
// 计算当前日期
getTody() {
// 计算当前日期
const date = new Date()
// 年月日
const year = date.getFullYear()
const month = date.getMonth() + 1
const day = date.getDate()
return `${year}/${month}/${day}` //Date内置对象基本使用,见ArkTs语法(1)
}
//点击事件
@State clickcolor: number = 0
build() {
Column() {
// 底部区域
Stack({ alignContent: Alignment.Top }) {
// 背景图
Image($r('app.media.ic_bg_517'))
.height(180)
.width('100%')
// 操作栏
Stack() {
Row() {
// 左
Image($r('app.media.ic_public_arrow_left'))
.width(24)
.fillColor(Color.White)
// 右
Row({ space: 10 }) {
Image($r('app.media.ic_public_question'))
.width(24)
.fillColor(Color.White)
Image($r('app.media.ic_public_share'))
.width(24)
.fillColor(Color.White)
}
}
.width('100%')
.justifyContent(FlexAlign.SpaceBetween)
// 中间文本
Column() {
Row() {
Text('英雄热度榜')
.fontColor(Color.White)
Image($r('app.media.ic_public_arrow_down'))
.width(20)
.fillColor(Color.White)
}
Row({ space: 5 }) {
Text('更新时间:' + this.today)
.fontColor(Color.White)
.fontSize(10)
Text('算法测试中')
.fontColor(Color.White)
.fontSize(9)
.backgroundColor('37bdee')
.padding(1)
.borderRadius({ topLeft: 6, bottomRight: 6 })
}
}
.layoutWeight(1)
}
.padding({ top: 10, left: 10, right: 10 })
.zIndex(2)
.height(55)
.backgroundColor(`rgba(0, 0, 0, 0.2)`)
}
// 筛选区域
// 段位筛选 tabFilter
List({ space: 25 }) {
ForEach(this.branchList, (item: string, index: number) => {
ListItem() {
Stack({ alignContent: Alignment.Bottom }) {
Text(item)
.height(40)
.padding(10)
.fontSize(16)
.fontColor(this.selectedIndex == index ? Color.Black : '#aab1b4') // 默认'#aab1b4'/ 高亮 black
//做判断 底部的横线 高亮时显示,反之隐藏
if (this.selectedIndex == index) {
Text()
.height(4)
.width(20)
.borderRadius(2)
.backgroundColor(Color.Orange)
}
}
.height(40)
}
.onClick(() => {
this.selectedIndex = index
if (item == '全部分路') {
this.heroList = heroList //当点击‘全部分路’时重新初始化数组,保证能成功渲染
} else {
this.heroList = heroList.filter((yx) => { //筛选符合条件的对象进行渲染
return yx.branchRoads.indexOf(item)!=-1 //indexOf判断branchRoads数组内是否有item,如果有返回数组下标,则不会等于-1
})
}
})
})
}
.listDirection(Axis.Horizontal)
.scrollBar(BarState.Off)
.width('100%')
.height(50)
// 英雄列表
Column() {
// 顶部区域
Row() {
Text('英雄')
.fontWeight(900)
Blank()
Row({ space: 10 }) {
ForEach(this.sortList, (item: string, index: number) => {
Text(item)
.fontWeight(900)
.fontColor(this.clickcolor == index ? '#37bdee' : Color.Black) //字体颜色高亮显示,通过状态变量的改变来改变渲染
.onClick(() => {
this.clickcolor = index
this.isUpperSort = !this.isUpperSort
//判断当高亮显示某个条件时列表如何排列
if (this.clickcolor == 0) {
this.heroList.sort((a, b) => { //sort数组元素排列
return this.isUpperSort ? b.orderNum * 1000 - a.orderNum * 1000 :
a.orderNum * 1000 - b.orderNum * 1000
})
} else
if (this.clickcolor == 1) {
this.heroList.sort((a, b) => {
return this.isUpperSort ? b.winRate * 1000 - a.winRate * 1000 :
a.winRate * 1000 - b.winRate * 1000
})
} else
if (this.clickcolor == 2) {
this.heroList.sort((a, b) => {
return this.isUpperSort ? b.showRate * 1000 - a.showRate * 1000 :
a.showRate * 1000 - b.showRate * 1000
})
} else
if (this.clickcolor == 3) {
this.heroList.sort((a, b) => {
return this.isUpperSort ? b.banRate * 1000 - a.banRate * 1000 :
a.banRate * 1000 - b.banRate * 1000
})
}
})
})
}
}
.width('100%')
.padding(10)
// 列表区域
List() {
ForEach(this.heroList, (item: Hero, index: number) => {
ListItem() {
Row({ space: 14 }) {
// 头像
Image(item.heroIcon)
.width(40)
.borderRadius(10)
// 昵称+分类
Column({ space: 5 }) {
Text(item.heroName)
Text(item.heroCareer)
.fontSize(10)
.fontColor(Color.Gray)
}
.width(85)
.alignItems(HorizontalAlign.Start)
// 热度 胜率 登场率 Ban 率
Text(item.tRank.toUpperCase())
.fontWeight(900)
.fontColor(this.clickcolor == 0 ? '#37bdee' : Color.Black) // 高亮 '#37bdee' 默认 Color.Black
Text((item.winRate * 100).toFixed(1)
.toString() + '%')
.width(45)
.fontSize(15)
.fontColor(this.clickcolor == 1 ? '#37bdee' : Color.Black)
Text((item.showRate * 100).toFixed(1)
.toString() + '%')
.width(45)
.fontSize(15)
.fontColor(this.clickcolor == 2 ? '#37bdee' : Color.Black)
Text((item.banRate * 100).toFixed(1)
.toString() + '%')
.width(45)
.fontSize(15)
.fontColor(this.clickcolor == 3 ? '#37bdee' : Color.Black)
}
.width('100%')
}
.padding(10)
.height(60)
})
}
.layoutWeight(1)
}
.layoutWeight(1)
}
.width('100%')
.height('100%')
}
}
-
拓展
上述案例中,为什么在计算胜率,登场率,ban率时在获取数字后加上了*1000呢?
这是一个浮点数精度丢失问题
0.1和0.2在二进制中却是一个表现不出来的无限不循环数,所以只能取一个近似数。 而计算机精度有限,所能表现的值而非真正的0.1,0.2,所以自然相加时会有偏差。
因此我们的解决方案是将数据放大1000倍让数据变成一个整数从而让他计算没有误差达到一个排序效果。
以上为个人总结,如有不足请指出~❤️