2020-07-12 15:26:34 +08:00

167 lines
2.9 KiB
JavaScript

import { createNamespace } from '../utils';
import { raf, cancelRaf } from '../utils/dom/raf';
import { isSameSecond, parseTimeData, parseFormat } from './utils';
const [createComponent, bem] = createNamespace('count-down');
export default createComponent({
props: {
millisecond: Boolean,
time: {
type: [Number, String],
default: 0,
},
format: {
type: String,
default: 'HH:mm:ss',
},
autoStart: {
type: Boolean,
default: true,
},
},
emits: ['change', 'finish'],
data() {
return {
remain: 0,
};
},
computed: {
timeData() {
return parseTimeData(this.remain);
},
formattedTime() {
return parseFormat(this.format, this.timeData);
},
},
watch: {
time: {
immediate: true,
handler() {
this.reset();
},
},
},
activated() {
if (this.keepAlivePaused) {
this.counting = true;
this.keepAlivePaused = false;
this.tick();
}
},
deactivated() {
if (this.counting) {
this.pause();
this.keepAlivePaused = true;
}
},
beforeDestroy() {
this.pause();
},
methods: {
// @exposed-api
start() {
if (this.counting) {
return;
}
this.counting = true;
this.endTime = Date.now() + this.remain;
this.tick();
},
// @exposed-api
pause() {
this.counting = false;
cancelRaf(this.rafId);
},
// @exposed-api
reset() {
this.pause();
this.remain = +this.time;
if (this.autoStart) {
this.start();
}
},
tick() {
if (this.millisecond) {
this.microTick();
} else {
this.macroTick();
}
},
microTick() {
this.rafId = raf(() => {
/* istanbul ignore if */
// in case of call reset immediately after finish
if (!this.counting) {
return;
}
this.setRemain(this.getRemain());
if (this.remain > 0) {
this.microTick();
}
});
},
macroTick() {
this.rafId = raf(() => {
/* istanbul ignore if */
// in case of call reset immediately after finish
if (!this.counting) {
return;
}
const remain = this.getRemain();
if (!isSameSecond(remain, this.remain) || remain === 0) {
this.setRemain(remain);
}
if (this.remain > 0) {
this.macroTick();
}
});
},
getRemain() {
return Math.max(this.endTime - Date.now(), 0);
},
setRemain(remain) {
this.remain = remain;
this.$emit('change', this.timeData);
if (remain === 0) {
this.pause();
this.$emit('finish');
}
},
},
render() {
return (
<div class={bem()}>
{this.$slots.default
? this.$slots.default(this.timeData)
: this.formattedTime}
</div>
);
},
});