countdown-pro
Version:
A simple countdown.
317 lines (312 loc) • 11.2 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.CountDown = factory());
})(this, (function () { 'use strict';
/**
* 前置补零,如果值的长度小于目标长度,则前置补零,否则不处理
*
* @param num 待处理的值
* @param targetLength 目标长度
* @returns 补零后的值
*/
function padZero(num, targetLength) {
if (targetLength === void 0) { targetLength = 2; }
var str = '' + num;
while (str.length < targetLength) {
str = '0' + str;
}
return str;
}
var SECOND = 1000;
var MINUTE = 60 * SECOND;
var HOUR = 60 * MINUTE;
var DAY = 24 * HOUR;
var mathFloor = Math.floor;
/**
* 解析时间戳
*
* @param {number} timestamp 时间戳,单位毫秒
* @returns 包含日/时/分/秒/毫秒的对象
*/
function parseTimeData(timestamp) {
return {
days: mathFloor(timestamp / DAY),
hours: mathFloor((timestamp % DAY) / HOUR),
minutes: mathFloor((timestamp % HOUR) / MINUTE),
seconds: mathFloor((timestamp % MINUTE) / SECOND),
milliseconds: mathFloor(timestamp % SECOND)
};
}
/**
* 格式化时间格式
*
* @param format 时间格式,DD-日,HH-时,mm-分,ss-秒,SSS-毫秒
* @param timeData 包含日/时/分/秒/毫秒的对象
* @returns 返回格式化后的时间字符串
*/
function parseFormat(format, timeData) {
// eslint-disable-next-line prefer-const
var days = timeData.days, hours = timeData.hours, minutes = timeData.minutes, seconds = timeData.seconds, milliseconds = timeData.milliseconds;
if (format.indexOf('DD') === -1) {
hours += days * 24;
}
else {
format = format.replace('DD', padZero(days));
}
if (format.indexOf('HH') === -1) {
minutes += hours * 60;
}
else {
format = format.replace('HH', padZero(hours));
}
if (format.indexOf('mm') === -1) {
seconds += minutes * 60;
}
else {
format = format.replace('mm', padZero(minutes));
}
if (format.indexOf('ss') === -1) {
milliseconds += seconds * 1000;
}
else {
format = format.replace('ss', padZero(seconds));
}
return format.replace('SSS', padZero(milliseconds, 3));
}
/**
* 格式化时间
*
* @param {number} timestamp 时间戳,单位毫秒
* @param {string} [pattern='HH:mm:ss'] 时间格式,DD-日,HH-时,mm-分,ss-秒,SSS-毫秒。默认值为 HH:mm:ss
* @returns {string} 返回格式化后的时间字符串
*/
function format(timestamp, pattern) {
if (pattern === void 0) { pattern = 'HH:mm:ss'; }
var timeData = parseTimeData(timestamp);
return parseFormat(pattern, timeData);
}
var noop = function () { };
var defaultInterval = 1000;
/**
* 倒计时
*
* @param {Object} options 配置项
* @param {number} options.time 倒计时,单位毫秒
* @param {number} [options.interval=1000] 时间间隔,单位毫秒。默认 `1000`
* @param {Function} [options.onChange] 倒计时时间变动时触发
* @param {Function} [options.onEnd] 倒计时结束时触发
* @param {number} [options.adjustInterval] 自动校准倒计时时间间隔,单位毫秒。如果有值且大于 `0`,再开始倒计时时会执行自动校准定时任务。暂定或结束倒计时会停止定时任务。
* @returns
* @example
* const countdown = new Countdown({
* time: 60 * 1000
* interval: 1000,
* onChange(){},
* onEnd(){},
* adjustInterval: 10 * 1000
* });
*
* // 实例方法
* // 开始倒计时
* countdown.start();
*
* // 暂停倒计时
* countdown.pause();
*
* // 重置倒计时。先暂停再将倒计时时间重置
* countdown.reset();
*
* // 重置再开始倒计时
* countdown.restart();
*
* // 更新配置。如果更新 `time` 需要手动调用 `reset` 或 `restart` 方法才生效
* countdown.updateOptions(options);
*
* // 校准倒计时。在倒计时运行时才生效,如果需要校准会先暂停再开始。
* countdown.adjustTime();
*
* // 静态方法
* // 格式化时间,返回格式化后的时间字符串
* CountDown.format(2 * 60 * 60 * 1000); // "02:00:00"
* CountDown.format(2 * 60 * 60 * 1000, 'mm:ss'); // "120:00"
*
* // 前置补零,返回补零后的值
* CountDown.padZero(2); // "02"
*
* // 解析时间戳,返回的时间对象格式
* CountDown.parseTimeData(2 * 60 * 60 * 1000);
* // {days: 0, hours: 2, minutes: 0, seconds: 0, milliseconds: 0}
*
*/
var CountDown = /** @class */ (function () {
function CountDown(options) {
this.options = this.o = {
onChange: noop,
onEnd: noop,
interval: defaultInterval,
time: 0,
adjustInterval: 0
};
this.updateOptions(options);
this.timer = null;
this.counting = false;
this.completed = false;
this.currentTime = this.o.time;
this.adjustStartTime = 0;
this.adjustCurrentTime = 0;
this.adjustTimer = null;
}
CountDown.prototype._handleEnd = function () {
clearInterval(this.adjustTimer);
this.counting = false;
this.completed = true;
this.o.onEnd();
};
/**
* 更新配置。
*
* 如果更新 `time` 需要手动调用 `reset` 或 `restart` 方法才生效。
*
* @param {Object} options 配置项
* @param {number} [options.time] 倒计时,单位毫秒
* @param {number} [options.interval] 时间间隔,单位毫秒
* @param {Function} [options.onChange] 倒计时时间变动时触发
* @param {Function} [options.onEnd] 倒计时结束时触发
* @returns
*/
CountDown.prototype.updateOptions = function (options) {
if (typeof options === 'object') {
for (var prop in options) {
// @ts-ignore
if (options[prop] !== undefined) {
// @ts-ignore
this.o[prop] = options[prop];
}
}
}
// 倒计时长
if (typeof this.o.time !== 'number' || this.o.time < 0) {
this.o.time = 0;
}
// 倒计时间隔
if (typeof this.o.interval !== 'number' || this.o.interval < 0) {
this.o.interval = defaultInterval;
}
};
/**
* 开始倒计时
* @returns
*/
CountDown.prototype.start = function () {
var _this = this;
if (this.counting || this.completed) {
return;
}
this.adjustStartTime = Date.now();
this.adjustCurrentTime = this.currentTime;
if (this.o.adjustInterval > 0) {
this.adjustTimer = setInterval(function () {
_this.adjustTime();
}, this.o.adjustInterval);
}
this.counting = true;
this.tick();
};
/**
* 校准倒计时时间。建议使用 `adjustInterval` 配置。
*
* 仅在倒计时运行时才生效。如果需要校准,会先暂停,调用 `onChange` ,再开始倒计时。
*
* @example
* const interval = 1000;
* let timer = null;
* const countdown = new CountDown({
* time: 60 * 1000,
* interval,
* onEnd(){
* clearInterval(timer);
* }
* });
*
* // 每倒计时10次,校准一次倒计时时间
* const timer = setInterval(()=>{
* countdown.adjustTime();
* }, interval * 10);
*
*/
CountDown.prototype.adjustTime = function () {
if (this.counting) {
var currentTimestamp = Date.now();
var diffTime = currentTimestamp - this.adjustStartTime;
var diffTimeInt = Math.round(diffTime / this.o.interval) * this.o.interval;
var newCurrentTime = this.adjustCurrentTime - diffTimeInt;
if (newCurrentTime >= 0 && this.currentTime !== newCurrentTime) {
this.pause();
this.currentTime = newCurrentTime;
this.o.onChange(this.currentTime);
if (this.currentTime === 0) {
this._handleEnd();
}
else {
this.start();
}
}
}
};
/**
* 暂停倒计时
*/
CountDown.prototype.pause = function () {
if (this.counting) {
clearTimeout(this.timer);
clearInterval(this.adjustTimer);
this.counting = false;
}
};
/**
* 重置倒计时。
*
* 先暂停再将倒计时时间重置。
*/
CountDown.prototype.reset = function () {
this.pause();
this.completed = false;
if (this.currentTime !== this.o.time) {
this.currentTime = this.o.time;
this.o.onChange(this.currentTime);
}
};
/**
* 重置再开始倒计时
*/
CountDown.prototype.restart = function () {
this.reset();
this.start();
};
CountDown.prototype.tick = function () {
var _this = this;
var interval = this.o.interval;
this.timer = setTimeout(function () {
_this.currentTime -= interval;
if (_this.currentTime < 0) {
_this.currentTime = 0;
}
_this.o.onChange(_this.currentTime);
if (_this.currentTime === 0) {
_this._handleEnd();
}
else {
_this.tick();
}
}, interval);
};
CountDown.format = format;
CountDown.parseTimeData = parseTimeData;
CountDown.parseFormat = parseFormat;
CountDown.padZero = padZero;
return CountDown;
}());
return CountDown;
}));
//# sourceMappingURL=countdown.umd.js.map