基于typeScript 封装倒计时,传入时间与step,实现倒计时

1,737 阅读1分钟

一、 定义倒计时状态

//设置格式
export interface RemainTimeData {
    /** 天数 */
    days: number;
    /** 小时数 */
    hours: number;
    /** 分钟数 */
    minutes: number;
    /** 秒数 */
    seconds: number;
    /** 毫秒数 */
    count: number;
}
enum CountdownStatus {
    running,    // 运行中
    paused,     // 暂停
    stoped,     // 结束
}
export enum CountdownEventName {
    START = 'start',
    STOP = 'stop',
    RUNNING = 'running',
}
interface CountdownEventMap {
    [CountdownEventName.START]: [];
    [CountdownEventName.STOP]: [];
    [CountdownEventName.RUNNING]: [RemainTimeData, number];
}

二、约束事件类型

import { EventEmitter } from 'eventemitter3';
export class Countdown extends EventEmitter<CountdownEventMap> {
    //定义参数
    private static COUNT_IN_MILLISECOND: number = 1 * 100;
    private static SECOND_IN_MILLISECOND: number = 10 * Countdown.COUNT_IN_MILLISECOND;
    private static MINUTE_IN_MILLISECOND: number = 60 * Countdown.SECOND_IN_MILLISECOND;
    private static HOUR_IN_MILLISECOND: number = 60 * Countdown.MINUTE_IN_MILLISECOND;
    private static DAY_IN_MILLISECOND: number = 24 * Countdown.HOUR_IN_MILLISECOND;
    //声明状态
    private endTime: number;
    private remainTime: number = 0;
    private status: CountdownStatus = CountdownStatus.stoped;
    private step: number;
    // 传入结束时间,多少秒跳动一次
    constructor(endTime: number, step: number = 1e3) {
        super();
        //赋值
        this.endTime = endTime;
        this.step = step;
        this.start();
    }

三、对应不同的状态,实现方法

public start() {
    // 通过emit通知外界,订阅
    this.emit(CountdownEventName.START);
    // 更新状态
    this.status = CountdownStatus.running;
    this.countdown();
}
 public stop() {
    this.emit(CountdownEventName.STOP);
    this.status = CountdownStatus.stoped;
}

四、递归 实现具体的倒计时逻辑

private countdown() {
    // 借鉴promise思想 判断状态不是running再执行具体逻辑
    if (this.status !== CountdownStatus.running) {
        return;
    }
    // 处理剩余时间,得到正数,如果是负数则会返回0
    this.remainTime = Math.max(this.endTime - Date.now(), 0);
    // 报告状态  传入格式参数与原始数据
    this.emit(CountdownEventName.RUNNING, this.parseRemainTime(this.remainTime), this.remainTime);
    // 判断如果还有剩余时间,则进行递归,继续调用当前函数;否则结束倒计时
    if (this.remainTime > 0) {
        // requsetAnimationFrame
        setTimeout(() => this.countdown(), this.step);
    } else {
        this.stop();
    }
}

五、强制返回定义类型

private parseRemainTime(remainTime: number): RemainTimeData {
    let time = remainTime;
    // 计算出具体的时间格式
    const days = Math.floor(time / Countdown.DAY_IN_MILLISECOND);
    time = time % Countdown.DAY_IN_MILLISECOND;

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

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

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

    const count = Math.floor(time / Countdown.COUNT_IN_MILLISECOND);

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

六、外部使用

public created() {
    // 传入结束时间与跳动时间
    const countdown = new Countdown(Date.now() + 60 * 60 * 1000, 10);
    countdown.on(CountdownEventName.RUNNING, (remainTimeData) => {
        const { hours, minutes, seconds, count} = remainTimeData;
        this.timeDisplay = [hours, minutes, seconds, count].map(fillZero).join(':');
    });
}

效果

WeChat01d74650d4273b7ab0cb0691cad1a7cd.png