UNPKG

@ciri/ngx-countdown

Version:
461 lines (454 loc) 12.4 kB
import { EventEmitter, Component, ChangeDetectionStrategy, ChangeDetectorRef, Input, Output, NgModule } from '@angular/core'; import { interval } from 'rxjs'; import { animationFrame } from 'rxjs/internal/scheduler/animationFrame'; import { CommonModule } from '@angular/common'; /** * @fileoverview added by tsickle * Generated from: lib/utils.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @param {?} num * @param {?=} n * @return {?} */ function padZero(num, n) { if (n === void 0) { n = 2; } /** @type {?} */ var str = num + ''; if (str.length >= n) { return str; } return (Array(n).join('0') + str).slice(-n); } /** @type {?} */ var SECOND = 1000; /** @type {?} */ var MINUTE = 60 * SECOND; /** @type {?} */ var HOUR = 60 * MINUTE; /** @type {?} */ var DAY = 24 * HOUR; /** * @param {?} time * @return {?} */ function parseTimeData(time) { /** @type {?} */ var days = Math.floor(time / DAY); /** @type {?} */ var hours = Math.floor((time % DAY) / HOUR); /** @type {?} */ var minutes = Math.floor((time % HOUR) / MINUTE); /** @type {?} */ var seconds = Math.floor((time % MINUTE) / SECOND); /** @type {?} */ var milliseconds = Math.floor(time % SECOND); return { days: days, hours: hours, minutes: minutes, seconds: seconds, milliseconds: milliseconds }; } /** * @param {?} format * @param {?} timeData * @return {?} */ function parseFormat(format, timeData) { 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)); } if (format.indexOf('S') !== -1) { /** @type {?} */ var ms = padZero(milliseconds, 3); if (format.indexOf('SSS') !== -1) { format = format.replace('SSS', ms); } else if (format.indexOf('SS') !== -1) { format = format.replace('SS', ms.slice(0, 2)); } else { format = format.replace('S', ms.charAt(0)); } } return format; } /** * @param {?} time1 * @param {?} time2 * @return {?} */ function isSameSecond(time1, time2) { return Math.floor(time1 / 1000) === Math.floor(time2 / 1000); } /** * @fileoverview added by tsickle * Generated from: lib/countdown.component.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @record */ function CountdownData() { } if (false) { /** @type {?} */ CountdownData.prototype.remain; /** @type {?} */ CountdownData.prototype.formattedTime; /** @type {?} */ CountdownData.prototype.fragments; } /** @enum {number} */ var CountdownState = { /** 暂停状态 */ paused: 0, /** 运行状态 */ playing: 1, /** 完成状态 */ finished: 2, }; CountdownState[CountdownState.paused] = 'paused'; CountdownState[CountdownState.playing] = 'playing'; CountdownState[CountdownState.finished] = 'finished'; /** * 所有组件实例使用同一个 interval 流,以免实例多了后造成卡顿 * @type {?} */ var instances = []; /** @type {?} */ var counter$ = interval(0, animationFrame); /** @type {?} */ var counterSub; /** * @return {?} */ function setupCounter() { destroyCounter(); counterSub = counter$.subscribe((/** * @return {?} */ function () { for (var i = 0; i < instances.length; i++) { /** @type {?} */ var inst = instances[i]; if (inst.state !== CountdownState.playing) { continue; } if (inst.remain <= 0) { inst.state = CountdownState.finished; inst.cdr.detectChanges(); inst.finish.emit(); continue; } /** @type {?} */ var remain = Math.max(inst.endTime - Date.now(), 0); if (!inst.millisecond) { if (!isSameSecond(remain, inst.remain) || remain === 0) { inst.remain = remain; inst.tick.emit(inst.remain); } } else { inst.remain = remain; inst.tick.emit(inst.remain); } inst.cdr.detectChanges(); } })); } /** * @return {?} */ function destroyCounter() { counterSub && counterSub.unsubscribe(); } /** * 倒计时组件 */ var CountdownComponent = /** @class */ (function () { function CountdownComponent(cdr) { this.cdr = cdr; /** * 格式 */ this.format = 'HH:mm:ss'; /** * 是否自动开始 */ this.autoStart = true; /** * 是否开启毫秒级渲染 */ this.millisecond = false; /** * 倒计时完毕时触发 */ this.finish = new EventEmitter(); /** * 每倒计时一次都触发 */ this.tick = new EventEmitter(); this.state = CountdownState.paused; this._time = 60000; } Object.defineProperty(CountdownComponent.prototype, "time", { get: /** * @return {?} */ function () { return this._time; }, /** 总毫秒数 */ set: /** * 总毫秒数 * @param {?} value * @return {?} */ function (value) { this._time = Math.max(value, 0); this.reset(); }, enumerable: true, configurable: true }); Object.defineProperty(CountdownComponent.prototype, "data", { get: /** * @return {?} */ function () { /** @type {?} */ var noMillisecond = this.format.indexOf('S') === -1; /** @type {?} */ var isPlaying = this.state === CountdownState.playing // 即使 format 中没有设置毫秒,程序计算时候也会将毫秒计算进去,导致运行时秒数看上去总是小 1 // 此处在渲染时候手动 +1 秒,以追求视觉统一 ; // 即使 format 中没有设置毫秒,程序计算时候也会将毫秒计算进去,导致运行时秒数看上去总是小 1 // 此处在渲染时候手动 +1 秒,以追求视觉统一 /** @type {?} */ var timeData = parseTimeData(this.remain + (noMillisecond && isPlaying ? 1000 : 0)); /** @type {?} */ var formattedTime = parseFormat(this.format, timeData); return { formattedTime: formattedTime, remain: this.remain, fragments: formattedTime.split(':') }; }, enumerable: true, configurable: true }); /** * @return {?} */ CountdownComponent.prototype.ngOnInit = /** * @return {?} */ function () { instances.push(this); if (instances.length === 1) { setupCounter(); } }; /** * @return {?} */ CountdownComponent.prototype.ngOnDestroy = /** * @return {?} */ function () { this.pause(); /** @type {?} */ var index = instances.indexOf(this); if (index !== -1) { instances.splice(index, 1); } if (instances.length === 0) { destroyCounter(); } }; /** * 继续倒计时 */ /** * 继续倒计时 * @return {?} */ CountdownComponent.prototype.start = /** * 继续倒计时 * @return {?} */ function () { if (this.state === CountdownState.playing) { return; } if (this.state === CountdownState.finished) { this.remain = this.time; } this.endTime = Date.now() + this.remain; this.state = CountdownState.playing; }; /** * 暂停倒计时 */ /** * 暂停倒计时 * @return {?} */ CountdownComponent.prototype.pause = /** * 暂停倒计时 * @return {?} */ function () { this.state = CountdownState.paused; }; /** * 重置倒计时 */ /** * 重置倒计时 * @return {?} */ CountdownComponent.prototype.reset = /** * 重置倒计时 * @return {?} */ function () { this.pause(); this.remain = this.time; this.cdr.detectChanges(); if (this.autoStart) { this.start(); } }; CountdownComponent.decorators = [ { type: Component, args: [{ selector: 'ngx-countdown', template: "<ng-container *ngIf=\"!render\">{{ data.formattedTime }}</ng-container>\n<ng-container *ngTemplateOutlet=\"render; context: { $implicit: data }\"></ng-container>\n", changeDetection: ChangeDetectionStrategy.OnPush }] } ]; /** @nocollapse */ CountdownComponent.ctorParameters = function () { return [ { type: ChangeDetectorRef } ]; }; CountdownComponent.propDecorators = { format: [{ type: Input }], autoStart: [{ type: Input }], millisecond: [{ type: Input }], render: [{ type: Input }], time: [{ type: Input }], finish: [{ type: Output }], tick: [{ type: Output }] }; return CountdownComponent; }()); if (false) { /** * 格式 * @type {?} */ CountdownComponent.prototype.format; /** * 是否自动开始 * @type {?} */ CountdownComponent.prototype.autoStart; /** * 是否开启毫秒级渲染 * @type {?} */ CountdownComponent.prototype.millisecond; /** * 自定义模版 * @type {?} */ CountdownComponent.prototype.render; /** * 倒计时完毕时触发 * @type {?} */ CountdownComponent.prototype.finish; /** * 每倒计时一次都触发 * @type {?} */ CountdownComponent.prototype.tick; /** @type {?} */ CountdownComponent.prototype.state; /** * @type {?} * @private */ CountdownComponent.prototype._time; /** * 剩余毫秒数 * @type {?} * @private */ CountdownComponent.prototype.remain; /** * @type {?} * @private */ CountdownComponent.prototype.endTime; /** * @type {?} * @private */ CountdownComponent.prototype.cdr; } /** * @fileoverview added by tsickle * Generated from: lib/countdown.module.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ var CountdownModule = /** @class */ (function () { function CountdownModule() { } CountdownModule.decorators = [ { type: NgModule, args: [{ declarations: [CountdownComponent], imports: [CommonModule], exports: [CountdownComponent] },] } ]; return CountdownModule; }()); /** * @fileoverview added by tsickle * Generated from: public-api.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /** * @fileoverview added by tsickle * Generated from: ciri-ngx-countdown.ts * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ export { CountdownComponent, CountdownModule, CountdownState }; //# sourceMappingURL=ciri-ngx-countdown.js.map