鸿蒙开发ArkTs语法(2)

551 阅读6分钟

鸿蒙开发ArkTs

1. 泛型

泛型在保证类型安全(不丢失类型信息)的同时,可以让函数等与多种不同的类型一起工作,灵活可复用

通俗一点就是:类型 是可变的!

  • 泛型函数

Type 是泛型参数的名字,类似于之前的形参,可自行定义。

基本语法:

function 函数名称<T>(形参:T) {
   let tmp:T = 形参
   return [形参]   // T[]
  }

举例:

image.png 参考代码:

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 约束的类型>(){}

image.png

  • 多个泛型参数

日常开发的时候,如果有需要可以添加多个 类型变量,只需要定义并使用 多个类型变量即可。同时多个类型都可以限制。如图:

image.png

  • 泛型接口、类

泛型同样可以在定义接口和类时使用。

基本语法:

interface 接口<Type>{
  // 内部使用Type
}

class 类名<Type>{
  // 内部可以使用 Type
}

2. 递归

递归就是一个函数(方法),在其方法体中调用自己。(需要有退出条件!)

作用:可以用来做无限层级数据的处理和展示。

基本语法:

function func(){
  func()
} //无限递归,没有退出条件(不可取)

演示案例:

image.png

参考代码:

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 次

正则表达式组合多种多样,深入研究的话极其耗费时间。建议了解即可,如果开发中需要用到了,建议问度娘🤪 跟我学习偷懒~

image.png

4. 数组常用 API

数组都是Array的实例化对象,鸿蒙开发中提供了很多的方法来供我们快速处理数据。常用的有:

方法名作用
indexof判断元素在数组中的索引,不存在返回-1
join根据传入内容拼接数组,默认为,返回拼接结果,字符串
forEach遍历数组,并且将数组的每一项作为参数传入到回调函数中,无返回值
map基于原数组,创建一个新数组
filter根据回调函数的执行结果,筛选出符合要求的元素,返回一个新数组
find返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined
findIndex返回数组中满足条件第一个元素的索引。若没有找到则返回 -1。
every返回数组中是否每一个元素都符合要求。
some返回数组中是否有一个元素符合要求。
sort方法的作用是对原数组的元素进行排序
reduce数组求和

更多参考链接

  • 数组常用API综合使用:

效果图:

wz.gif

参考代码:

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倍让数据变成一个整数从而让他计算没有误差达到一个排序效果。

以上为个人总结,如有不足请指出~❤️

image.png