使用TS实现一个可以处理事件的倒计时

1,457 阅读1分钟

目标

实现一个倒计时

要点

ts的实际应用

talk is cheap.png

Let's Go !!!

先来一个记录事件类型的枚举

export enum CountdownEventName {
    START = 'start',
    STOP = 'stop',
    RUNNING = 'running',
}

再来一个记录执行状态的枚举

enum CountdownStatus {
    running,
    paused,
    stoped,
}

来一个记录时分秒的interface

export interface RemainTimeDate {
    days: number;
    hours: number;
    minutes: number;
    seconds: number;
    count: number;
}

由于使用了EventEmitter这个库记得引入一下

import { EventEmitter } from 'eventemitter3'

处理倒计时的主入口

interface CountdownEventMap {
    [CountdownEventName.START] : [];
    [CountdownEventName.STOP] : [];
    [CountdownEventName.RUNNING] : [];
}
export class Countdown extends EventEmitter<CountdownEventMap> {
    // 定义一下 天 时 分 秒 毫秒(跳动步数)
    private static COUNT_IN_MILLSECOND: number = 1 * 100;
    private static SECOND_IN_MILLSECOND: number = 10 * Countdown.COUNT_IN_MILLSECOND;
    private static MINUTE_IN_MILLSECOND: number = 60 * Countdown.SECOND_IN_MILLSECOND;
    private static HOUR_IN_MILLSECOND: number = 60 * Countdown.MINUTE_IN_MILLSECOND;
    private static DAY_IN_MILLSECOND: number = 24 * Countdown.HOUR_IN_MILLSECOND;
    
    private endTime: number; // 结束时间
    private step: number; // 毫秒步数间隔
    private remainTime: number = 0; // 倒计时剩余时间
    private status: CountdownStatus = CountdownStatus.stoped; // 当前倒计时执行状态
    
    constructor(endTime: number, step: number = 1e3) {
        super() // 继承父类
        this.endTime = endTime
        this.step = step
    }
}

再定义一下不同状态的执行函数

// 倒计时开始
public start() {
    this.emit(CountdownEventName.START)
    this.status = CountdownStatus.running
    this.countdown()
}

// 倒计时结束
public stop() {
    this.emit(CountdownEventName.STOP)
    this.status = CountdownStatus.stoped
}

// 倒计时执行函数
private countdown() {
    if (this.status !== CountdownStatus.running) {
        return
    }

    this.remainTime = Math.max(this.endTime - Date.now(), 0)
    this.emit(CountdownEventName.RUNNING, this.parseRemainTime(this.remainTime))

    if (this.remainTime > 0) {
        setTimeout(() => {
            this.countdown()
        }, this.step)
    } else {
        this.stop()
    }
}

最后封装一个剩余时间的处理函数

// 很简单所以不加注释了,新手司机都可以看懂
private parseRemainTime(remainTime: number): RemainTimeDate {
    let time = remainTime
    const days = Math.floor(time / Countdown.DAY_IN_MILLSECOND)
    time = time % Countdown.DAY_IN_MILLSECOND

    const hours = Math.floor(time / Countdown.HOUR_IN_MILLSECOND)
    time = time % Countdown.HOUR_IN_MILLSECOND

    const minutes = Math.floor(time / Countdown.MINUTE_IN_MILLSECOND)
    time = time % Countdown.MINUTE_IN_MILLSECOND

    const seconds = Math.floor(time / Countdown.SECOND_IN_MILLSECOND)
    time = time % Countdown.SECOND_IN_MILLSECOND

    const count = Math.floor(time / Countdown.COUNT_IN_MILLSECOND)

    return {
        days,
        hours,
        minutes,
        seconds,
        count,
    }
}

大功告成,我们去使用一下

const countdown = new Countdown(Date.now() + 60 * 60 * 1000, 1000)
countdown.on(CountdownEventName.RUNNING, remainTimeDate => {
    const { hours, minutes, seconds, count } = remainTimeDate
    // 定义一个变量接收然后展示到页面中,具体效果不在展示
    let timeDisplay = [hours, minutes, seconds, count].map.join(':')
    // 00:59:59:11
}

补充:

  • 这么做的好处是什么?
  1. 首先可以实时的开启和停止倒计时
  2. stop的回调函数countdown.on(CountdownEventName.STOP, () => { // todo })