定时器
日常开发中如果需要代码 延迟一会执行,或者每隔一段时间执行一次,就可以使用定时器
定时器有两种:
- setTimeout: 延迟执行
- setInterval: 间隔执行
setTimeout
setTimeout可以用来设置一个定时器,当设置的时间到了之后就会去执行指定的函数
执行一次用 setTimeout
场景如下:
定义setTimeout的基本语法
// setTimout会返回一个数字,表示当前延迟器的标记值
let 变量 = setTimeout(需要运行的函数,延迟时间单位毫秒)
//举例:
let timeId = setTimeout(()=>{
console.log('我被执行了') // ✨✨✨只执行一次
} , 1000)
清除setTimeout的执行
clearTimeout(setTimout的标记值)
//举例:
// 1. 创建延迟器,使用timeId保存延迟器的标记值
let timeId = setTimeout(()=>{
console.log('我被执行了')
} , 3000)
// 2. 清除延迟器的继续执行
clearTimeout(timeId)
小案例
@Entry
@Component
struct Index {
@State msg:string = 'setTimeout延时器'
timeId?:number
build() {
Column() {
Text(this.msg)
.fontSize(30)
Row() {
Button('开启延时器')
.onClick(()=>{
this.timeId = setTimeout(()=>{
this.msg = '我被修改了'
},2000)
})
Button('清楚延时器')
.onClick(()=>{
clearTimeout(this.timeId)
})
}
}
.width('100%')
.height('100%')
.backgroundColor(Color.Pink)
}
}
setInterval
setInterval 也是可以用来设置一个定时器,根据设置的时间间隔来执行指定的函数
执行多次用 setInterval!!
场景如下:
定义setInterval的基本语法
// setInterval会返回一个数字,表示当前定时器的标记值
let 变量 = setInterval(需要运行的函数,定时器执行间隔单位毫秒)
//举例:
let timeId = setInterval(()=>{
console.log('我被执行了') // ✨✨✨每隔1秒执行一次
} ,
1000) // ✨✨每隔1秒执行一次 , 1秒 = 1000毫秒
清除setInterval的执行
clearInterval(setInterval的标记值)
//举例:
// 1. 创建定时器,使用timeId保存延迟器的标记值
let timeId = setTInterval(()=>{
console.log('我被执行了')
} , 3000)
// 2. 清除定时器器的继续执行
clearInterval(timeId)
案例-获取验证码
需求:
- 获取验证码(setTimout的使用练习)
a. 点击【发送验证码】按钮之后,延迟 2 秒(setTimeout)获取一个 4 位的随机数(Math.floor(1000+Math.random()*9000)),通过弹框显示出来(AlertDialog.show({message:})) - 倒计时效果(setInterval的使用练习)
a. 点击【发送验证码】后 -> 文字变开始每隔1秒钟切换显示【xx秒后获取】 ,倒计时达到0秒的时候,恢复显示未【发送验证码】文字,并清除定时器
代码如下:
@Entry
@Component
struct Index {
@State time:number = 0 //控制倒计时
timeId?:number //
build() {
Column() {
this.titleBuilder()
TextInput({ placeholder: '请输入手机号' })
.textInputExtend()
Divider()
Row() {
TextInput({ placeholder: '请输入验证码' })
.textInputExtend()
.layoutWeight(1)
Text(this.time == 0 ?'发送验证码':`${this.time}秒后获取`)
.fontSize(14)
.fontColor(Color.Gray)
.onClick(()=>{
// 防止在 倒计时 时重复点击
if(this.time != 0){
return
}
//1. 4位随机数
let randomNum = Math.floor(Math.random()*9000 + 1000)
//2. 2秒后提示
setTimeout(()=>{
AlertDialog.show({message:randomNum.toString()})
},2000)
// 60秒倒计时
this.time = 60
this.timeId = setInterval(()=>{
this.time--
if(this.time<=0){ //倒计时为0时清楚定时器
clearInterval(this.timeId)
}
},1000)
})
}
.width('100%')
Divider()
Button('登录')
.width('100%')
.type(ButtonType.Normal)
.backgroundColor('#ea6051')
.margin({ top: 50 })
}
.padding({ top: 80, left: 40, right: 40 })
.width('100%')
.alignItems(HorizontalAlign.Start)
}
@Builder
titleBuilder() {
Text('短信登录')
.fontSize(25)
.fontWeight(600)
.margin({ bottom: 30 })
}
}
@Extend(TextInput)
function textInputExtend() {
.backgroundColor(Color.White)
.padding({ left: 0, top: 20, bottom: 20 })
.placeholderColor('#ccc')
}
递归
基本用法
一个函数(方法) ,在其方法体中调用自己的写法就是递归
// 没有退出条件的 递归函数--无限递归
function func(){
func()
}
//调用 执行函数
func()
递归必须有退出条件
为了防止无限递归导致崩溃,我们在做具体递归调用时,必须设置退出条件
function printLog(num: number) {
console.log(`你好,第${num}次打印`)
// 递减
num--
// 退出条件
if (num > 0) {
printLog(num)
}
}
// 打印 2 次
printLog(2)
常用内置对象
Math 对象
拥有一些数学常数属性和数学函数方法。Math 的所有属性与方法都是静态的,使用的时候直接通过Math点出来即可
常用属性
Math.PI
圆周率,一个圆的周长和直径之比,约等于 3.14159。
console.log(Math.PI.toString())
常用方法
| 方法 | 说明 |
|---|---|
| Math.random() | 返回一个 0 到 1 之间的伪随机数。 |
| Math.ceil(x) | 返回大于一个数的最小整数,即一个数向上取整后的值。 |
| Math.floor(x) | 返回小于一个数的最大整数,即一个数向下取整后的值。 |
| Math.round(x) | 返回四舍五入后的整数。 |
| Math.abs(x) | 返回一个数的绝对值 |
| Math.max([x[,y[, …]]]) | 返回零到多个数值中最大值。 |
| Math.min([x[,y[, …]]]) | 返回零到多个数值中最小值。 |
const numA: number = 1.5
console.log(Math.ceil(numA) + '') // 向上取整 2
console.log(Math.floor(numA) + '') // 向下取整 1
console.log(Math.round(numA) + '') // 四舍五入 2
const numB:number = -9
console.log(Math.abs(numB) + '') // 绝对值 9
const numList: number[] = [13, 2, 31, 42, 15, 56, 27, 28]
const max: number = Math.max(...numList)
const min: number = Math.min(...numList)
console.log('max:', max) // 最大值
console.log('min:', min) // 最小值
// 0-1 取得到0,取不到 1
console.log(Math.random() + '')
// 返回 0-n的随机数的函数
function getRandomArbitrary(max: number): number {
return Math.floor(Math.random() * (max + 1))
}
// 返回 min-max 的随机数的函数
function getRandomIntInclusive(min: number, max: number): number {
return Math.floor(Math.random() * (max - min + 1)) + min; //含最大值,含最小值
}
Date 对象
用来创建、解析、操作日期和时间。
// 获取当前日期
let date1 = new Date()
console.log('date1:',date1)
//获取指定日期
let date2 = new Date('1995-01-01T01:11:00')
console.log('date2:',date2)
// Unix时间戳 是指从1970年1月1日(UTC)开始到现在经历的时间(毫秒)
let date3 = new Date(1706170405708)
console.log('date3:',date3)
常用方法
实例方法
| 方法名 | 作用 | 说明 |
|---|---|---|
| getFullYear | 获取年份 | 4 位数年份 |
| getMonth | 获取月份 | 取值 0-11 |
| getDate | 获取日期 | 月份中的日期 |
| getHours | 获取小时 | 无 |
| getMinutes | 获取分钟 | 无 |
| getSeconds | 获取秒 | 无 |
| getDay | 获取星期 | 周日为 0 |
静态方法
| 方法名 | 作用 | 说明 |
|---|---|---|
| now | 获取当前时间 | 时间戳 |
//实例方法
console.log('年',new Date().getFullYear())
console.log('月',new Date().getMonth()+1)
console.log('日',new Date().getDate())
console.log('时',new Date().getHours())
console.log('分',new Date().getMinutes())
console.log('秒',new Date().getSeconds())
console.log('星期',new Date().getDay())
//静态方法 得到的值是一个时间戳
console.log('',Date.now())
案例-时钟
代码如下:
@Entry
@Component
struct Date01 {
// 1. 获取当前日期
getNow() {
let date = new Date()
let year = date.getFullYear()
let month = date.getMonth() + 1
let day = date.getDate()
return `${year}年${month}月${day}日`
}
// 2. 获取星期
getWeek() {
let date = new Date()
let weekDay = date.getDay() // 周日为0
let resWeek = ''
switch (weekDay) {
case 0:
resWeek = '周日'
break
case 1:
resWeek = '周一'
break
case 2:
resWeek = '周二'
break
case 3:
resWeek = '周三'
break
case 4:
resWeek = '周四'
break
case 5:
resWeek = '周五'
break
case 6:
resWeek = '周六'
break
default:
}
return resWeek
}
// 3. 设置时钟时间变化
@State hour: number = 0
@State min: number = 0
@State seconds: number = 0
build() {
Column() {
Column() {
Text(`${this.getNow()} ${this.getWeek()}`)
.fontColor(Color.White)
.fontSize(20)
Stack() {
Row({ space: 10 }) {
Text(this.hour < 10 ? '0' + this.hour : this.hour.toString())
.textStyle()
Text(this.min < 10 ? '0' + this.min : this.min.toString())
.textStyle()
Text(this.seconds < 10 ? '0' + this.seconds : this.seconds.toString())
.textStyle()
}
.onAppear(() => {
// 3. 设置时钟时间变化
setInterval(() => {
let date = new Date()
this.hour = date.getHours()
this.min = date.getMinutes()
this.seconds = date.getSeconds()
}, 1000)
})
Divider()
.strokeWidth(2)
.color(Color.Black)
}
.padding(10)
Text('求知若渴,虚心若愚')
.fontColor(Color.White)
.fontSize(18)
}
}
.width('100%')
.height('100%')
.backgroundColor(Color.Black)
.justifyContent(FlexAlign.Center)
}
}
@Extend(Text)
function textStyle() {
.width(100)
.height(100)
.backgroundColor('#191919')
.borderRadius(10)
.textAlign(TextAlign.Center)
.fontColor(Color.White)
.fontSize(70)
.fontWeight(900)
}
}
String
split(分隔)
split() 方法根据传入的内容将字符串分隔为数组
语法:字符串.split(分隔符)// 返回切割之后的数组
// 1. 切割为数组
const branchFilter: string = ' 全部分路 | 对抗路 | 中路 | 发育路 | 游走 | 打野 '
const tabFilter: string = ' 所有段位 - 巅峰赛1350+ - 顶端排位 - 赛事 '
// 2. 获取日期
const dateStr:string = '2024-04-27'
let arr1 = branchFilter.split('|')
console.log(JSON.stringify(arr1))
let arr2 = tabFilter.split('-')
console.log(JSON.stringify(arr2))
let arr3 = dateStr.split('-')
console.log(JSON.stringify(arr3))
trim(去空格)
trim方法会从字符串的两端移除空白字符,并返回一个【新的字符串】,而不会修改原始字符串。语法:字符串.trim()// 返回去除空格之后的字符串
// trim 去除两边空格
// 1.基础文本
const str: string = ' 123 '
console.log(str.trim()) // '123'
// 2.用户名
const username = ' jack '
console.log(username.trim()) // 'jack'
// 3.密码
const password = ' 1234abc '
console.log(password.trim()) // '1234abc'
toLowerCase(转小写) 和 toUpperCase(转大写)
语法:
字符串.toLowerCase()// 返回转为小写之后的字符串
字符串.toUpperCase()// 返回转为大写之后的字符串
includes(判断是否存在)
includes() 方法执行区分大小写的搜索,以确定是否可以在一个字符串中找到另一个字符串,并根据情况返回 true 或 false。
语法:字符串.includes(查询的字符串)// 返回判断结果 true / false
slice(提取)
slice方法提取字符串的一部分,并将其作为新字符串返回,而不修改原始字符串。
语法:
字符串.slice(起始索引)// 从起始索引切割到末尾
字符串.slice(起始索引,结束索引) // 从起始索引,切换到结束索引
案例-热度榜单
页面数据
创建 HeroData.ets 文件,参考路径如下: /data/HeroData.ets
export const branchFilter: string = ' 全部分路 | 对抗路 | 中路 | 发育路 | 游走 | 打野 '
// 英雄数据
export interface Hero {
banRate: number // ban 率
showRate: number // 登场率
winRate: number // 胜率
tRank: string // 热度
heroCareer: string // 英雄分类
heroName: string // 名字
heroIcon: ResourceStr // 头像
heroId: number // id
}
// 数组
export const heroList: Hero[] = [
{
banRate: 0.403,
winRate: 0.519,
showRate: 0.284,
tRank: 't0',
heroCareer: '辅助',
heroId: 505,
heroIcon: $r('app.media.ic_avatar_505'),
heroName: '瑶'
},
{
banRate: 0.702,
winRate: 0.477,
showRate: 0.097,
tRank: 't0',
heroCareer: '辅助',
heroId: 191,
heroIcon: $r('app.media.ic_avatar_191'),
heroName: '大乔'
},
{
banRate: 0.567,
winRate: 0.487,
showRate: 0.076,
tRank: 't0',
heroCareer: '辅助/坦克',
heroId: 187,
heroIcon: $r('app.media.ic_avatar_187'),
heroName: '东皇太一'
},
{
banRate: 0.452,
winRate: 0.512,
showRate: 0.12,
tRank: 't0',
heroCareer: '辅助/坦克',
heroId: 113,
heroIcon: $r('app.media.ic_avatar_113'),
heroName: '庄周'
},
{
banRate: 0.356,
winRate: 0.503,
showRate: 0.162,
tRank: 't0',
heroCareer: '辅助',
heroId: 184,
heroIcon: $r('app.media.ic_avatar_184'),
heroName: '蔡文姬'
},
{
banRate: 0.482,
winRate: 0.475,
showRate: 0.082,
tRank: 't0',
heroCareer: '辅助',
heroId: 159,
heroIcon: $r('app.media.ic_avatar_159'),
heroName: '朵莉亚'
},
{
banRate: 0.022,
winRate: 0.495,
showRate: 0.297,
tRank: 't0',
heroCareer: '法师',
heroId: 142,
heroIcon: $r('app.media.ic_avatar_142'),
heroName: '安琪拉'
},
{
banRate: 0.396,
winRate: 0.496,
showRate: 0.098,
tRank: 't0',
heroCareer: '法师',
heroId: 563,
heroIcon: $r('app.media.ic_avatar_563'),
heroName: '海诺'
},
]
实现
import { branchFilter, Hero, heroList } from '../data/HeroData' //导入数据
let branch = branchFilter.split('|') //把分路数据去分隔符形成数组
@Entry
@Component
struct Index {
// 日期
time() {
let time = new Date()
let year = time.getFullYear()
let month = time.getMonth() + 1
let day = time.getDate()
return `更新时间:${year}/${month}/${day}/`
}
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.time())
.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(branch, (item: string) => {
ListItem() {
Text(item.trim())
.height(40)
.padding(10)
.fontSize(16)
}
})
}
.listDirection(Axis.Horizontal)
.scrollBar(BarState.Off)
.width('100%')
.height(50)
// 英雄列表
Column() {
// 顶部区域
Row() {
Text('英雄')
.fontWeight(900)
Blank()
Row({ space: 10 }) {
Text('热度')
.fontWeight(900)
Text('胜率')
.fontWeight(900)
Text('登场率')
.fontWeight(900)
Text('Ban率')
.fontWeight(900)
}
}
.width('100%')
.padding(10)
// 列表区域
List() {
ForEach(heroList, (item: Hero) => {
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(70)
.alignItems(HorizontalAlign.Start)
Blank()
// 热度 胜率 登场率 Ban 率
Text(item.tRank.toUpperCase())
.fontWeight(900)
Text(`${(item.winRate * 100).toFixed(1)}%`) //给的数据是小数,变成百分比形式保留1位小数
.width(45)
.fontSize(15)
Text(`${(item.showRate * 100).toFixed(1)}%`)
.width(45)
.fontSize(15)
Text(`${(item.banRate * 100).toFixed(1)}%`)
.width(45)
.fontSize(15)
}
.width('100%')
}
.padding(10)
})
}
}
.layoutWeight(1)
}
.width('100%')
.height('100%')
}
}