From 8e5c8f2f89b6b53e24615c06b38dfd558149e6b1 Mon Sep 17 00:00:00 2001 From: chenjiahan Date: Tue, 6 Oct 2020 09:22:54 +0800 Subject: [PATCH] chore(CountDown): extract useCountDown --- src/count-down/README.md | 29 +++--- src/count-down/README.zh-CN.md | 31 +++---- src/count-down/index.js | 125 ++++---------------------- src/count-down/use-count-down.ts | 149 +++++++++++++++++++++++++++++++ src/count-down/utils.ts | 36 +------- 5 files changed, 203 insertions(+), 167 deletions(-) create mode 100644 src/count-down/use-count-down.ts diff --git a/src/count-down/README.md b/src/count-down/README.md index 9ad60e550..64fef8755 100644 --- a/src/count-down/README.md +++ b/src/count-down/README.md @@ -134,26 +134,27 @@ export default { ### Events -| Event | Description | Arguments | -| --------------- | ---------------------------------- | -------------------- | -| finish | Triggered when count down finished | - | -| change `v2.4.4` | Triggered when count down changed | _timeData: TimeData_ | +| Event | Description | Arguments | +| --- | --- | --- | +| finish | Triggered when count down finished | - | +| change `v2.4.4` | Triggered when count down changed | _currentTime: CurrentTime_ | ### Slots -| Name | Description | SlotProps | -| ------- | -------------- | -------------------- | -| default | Custom Content | _timeData: TimeData_ | +| Name | Description | SlotProps | +| ------- | -------------- | -------------------------- | +| default | Custom Content | _currentTime: CurrentTime_ | ### TimeData Structure -| Name | Description | Type | -| ------------ | ------------------- | -------- | -| days | Remain days | _number_ | -| hours | Remain hours | _number_ | -| minutes | Remain minutes | _number_ | -| seconds | Remain seconds | _number_ | -| milliseconds | Remain milliseconds | _number_ | +| Name | Description | Type | +| ------------ | ----------------------------- | -------- | +| total | Total time, unit milliseconds | _number_ | +| days | Remain days | _number_ | +| hours | Remain hours | _number_ | +| minutes | Remain minutes | _number_ | +| seconds | Remain seconds | _number_ | +| milliseconds | Remain milliseconds | _number_ | ### Methods diff --git a/src/count-down/README.zh-CN.md b/src/count-down/README.zh-CN.md index 6f14effb6..7e3600bd6 100644 --- a/src/count-down/README.zh-CN.md +++ b/src/count-down/README.zh-CN.md @@ -144,26 +144,27 @@ export default { ### Events -| 事件名 | 说明 | 回调参数 | -| --------------- | ---------------- | -------------------- | -| finish | 倒计时结束时触发 | - | -| change `v2.4.4` | 倒计时变化时触发 | _timeData: TimeData_ | +| 事件名 | 说明 | 回调参数 | +| --------------- | ---------------- | -------------------------- | +| finish | 倒计时结束时触发 | - | +| change `v2.4.4` | 倒计时变化时触发 | _currentTime: CurrentTime_ | ### Slots -| 名称 | 说明 | SlotProps | -| ------- | ---------- | -------------------- | -| default | 自定义内容 | _timeData: TimeData_ | +| 名称 | 说明 | SlotProps | +| ------- | ---------- | -------------------------- | +| default | 自定义内容 | _currentTime: CurrentTime_ | -### TimeData 格式 +### CurrentTime 格式 -| 名称 | 说明 | 类型 | -| ------------ | -------- | -------- | -| days | 剩余天数 | _number_ | -| hours | 剩余小时 | _number_ | -| minutes | 剩余分钟 | _number_ | -| seconds | 剩余秒数 | _number_ | -| milliseconds | 剩余毫秒 | _number_ | +| 名称 | 说明 | 类型 | +| ------------ | ---------------------- | -------- | +| total | 剩余总时间(单位毫秒) | _number_ | +| days | 剩余天数 | _number_ | +| hours | 剩余小时 | _number_ | +| minutes | 剩余分钟 | _number_ | +| seconds | 剩余秒数 | _number_ | +| milliseconds | 剩余毫秒 | _number_ | ### 方法 diff --git a/src/count-down/index.js b/src/count-down/index.js index 33a135b1a..f571e5724 100644 --- a/src/count-down/index.js +++ b/src/count-down/index.js @@ -1,18 +1,12 @@ -import { - ref, - watch, - computed, - onActivated, - onDeactivated, - onBeforeUnmount, -} from 'vue'; +import { watch, computed } from 'vue'; // Utils -import { raf, cancelRaf, createNamespace } from '../utils'; -import { isSameSecond, parseTimeData, parseFormat } from './utils'; +import { createNamespace } from '../utils'; +import { parseFormat } from './utils'; // Composition import { useExpose } from '../composition/use-expose'; +import { useCountDown } from './use-count-down'; const [createComponent, bem] = createNamespace('count-down'); @@ -36,118 +30,37 @@ export default createComponent({ emits: ['change', 'finish'], setup(props, { emit, slots }) { - let rafId; - let endTime; - let counting; - let keepAlived; - - const remain = ref(0); - const timeData = computed(() => parseTimeData(remain.value)); - const timeText = computed(() => parseFormat(props.format, timeData.value)); - - const pause = () => { - counting = false; - cancelRaf(rafId); - }; - - const getCurrentRemain = () => Math.max(endTime - Date.now(), 0); - - const setRemain = (value) => { - remain.value = value; - emit('change', timeData.value); - - if (value === 0) { - pause(); + const { start, pause, reset, current } = useCountDown({ + time: +props.time, + millisecond: props.millisecond, + onChange(current) { + emit('change', current); + }, + onFinish() { emit('finish'); - } - }; + }, + }); - const microTick = () => { - rafId = raf(() => { - // in case of call reset immediately after finish - if (counting) { - setRemain(getCurrentRemain()); - - if (remain.value > 0) { - microTick(); - } - } - }); - }; - - const macroTick = () => { - rafId = raf(() => { - // in case of call reset immediately after finish - if (counting) { - const currentRemain = getCurrentRemain(); - - if ( - !isSameSecond(currentRemain, remain.value) || - currentRemain === 0 - ) { - setRemain(currentRemain); - } - - if (remain.value > 0) { - macroTick(); - } - } - }); - }; - - const tick = () => { - if (props.millisecond) { - microTick(); - } else { - macroTick(); - } - }; - - const start = () => { - if (!counting) { - endTime = Date.now() + remain.value; - counting = true; - tick(); - } - }; - - const reset = () => { - pause(); - remain.value = +props.time; + const timeText = computed(() => parseFormat(props.format, current.value)); + const resetTime = () => { + reset(+props.time); if (props.autoStart) { start(); } }; - watch(() => props.time, reset, { immediate: true }); - - onActivated(() => { - if (keepAlived) { - counting = true; - keepAlived = false; - tick(); - } - }); - - onDeactivated(() => { - if (counting) { - pause(); - keepAlived = true; - } - }); - - onBeforeUnmount(pause); + watch(() => props.time, resetTime, { immediate: true }); useExpose({ start, - reset, pause, + reset: resetTime, }); return () => (
- {slots.default ? slots.default(timeData.value) : timeText.value} + {slots.default ? slots.default(current.value) : timeText.value}
); }, diff --git a/src/count-down/use-count-down.ts b/src/count-down/use-count-down.ts new file mode 100644 index 000000000..5c4691e8d --- /dev/null +++ b/src/count-down/use-count-down.ts @@ -0,0 +1,149 @@ +import { + ref, + computed, + onActivated, + onDeactivated, + onBeforeUnmount, +} from 'vue'; +import { raf, cancelRaf } from '../utils'; +import { isSameSecond } from './utils'; + +export type CurrentTime = { + days: number; + hours: number; + total: number; + minutes: number; + seconds: number; + milliseconds: number; +}; + +export type UseCountDownOptions = { + time: number; + millisecond?: boolean; + onChange?: (current: CurrentTime) => void; + onFinish?: () => void; +}; + +const SECOND = 1000; +const MINUTE = 60 * SECOND; +const HOUR = 60 * MINUTE; +const DAY = 24 * HOUR; + +export function parseTime(time: number): CurrentTime { + const days = Math.floor(time / DAY); + const hours = Math.floor((time % DAY) / HOUR); + const minutes = Math.floor((time % HOUR) / MINUTE); + const seconds = Math.floor((time % MINUTE) / SECOND); + const milliseconds = Math.floor(time % SECOND); + + return { + total: time, + days, + hours, + minutes, + seconds, + milliseconds, + }; +} + +export function useCountDown(options: UseCountDownOptions) { + let rafId: number; + let endTime: number; + let counting: boolean; + let deactivated: boolean; + + const remain = ref(options.time); + const current = computed(() => parseTime(remain.value)); + + const pause = () => { + counting = false; + cancelRaf(rafId); + }; + + const getCurrentRemain = () => Math.max(endTime - Date.now(), 0); + + const setRemain = (value: number) => { + remain.value = value; + options.onChange?.(current.value); + + if (value === 0) { + pause(); + options.onFinish?.(); + } + }; + + const microTick = () => { + rafId = raf(() => { + // in case of call reset immediately after finish + if (counting) { + setRemain(getCurrentRemain()); + + if (remain.value > 0) { + microTick(); + } + } + }); + }; + + const macroTick = () => { + rafId = raf(() => { + // in case of call reset immediately after finish + if (counting) { + const remainRemain = getCurrentRemain(); + + if (!isSameSecond(remainRemain, remain.value) || remainRemain === 0) { + setRemain(remainRemain); + } + + if (remain.value > 0) { + macroTick(); + } + } + }); + }; + + const tick = () => { + if (options.millisecond) { + microTick(); + } else { + macroTick(); + } + }; + + const start = () => { + if (!counting) { + endTime = Date.now() + remain.value; + counting = true; + tick(); + } + }; + + const reset = (totalTime: number) => { + pause(); + remain.value = totalTime; + }; + + onBeforeUnmount(pause); + + onActivated(() => { + if (deactivated) { + counting = true; + deactivated = false; + tick(); + } + }); + + onDeactivated(() => { + if (counting) { + pause(); + deactivated = true; + } + }); + + return { + start, + pause, + reset, + current, + }; +} diff --git a/src/count-down/utils.ts b/src/count-down/utils.ts index 3ab764c2c..5e25f9134 100644 --- a/src/count-down/utils.ts +++ b/src/count-down/utils.ts @@ -1,37 +1,9 @@ import { padZero } from '../utils'; +import { CurrentTime } from './use-count-down'; -export type TimeData = { - days: number; - hours: number; - minutes: number; - seconds: number; - milliseconds: number; -}; - -const SECOND = 1000; -const MINUTE = 60 * SECOND; -const HOUR = 60 * MINUTE; -const DAY = 24 * HOUR; - -export function parseTimeData(time: number): TimeData { - const days = Math.floor(time / DAY); - const hours = Math.floor((time % DAY) / HOUR); - const minutes = Math.floor((time % HOUR) / MINUTE); - const seconds = Math.floor((time % MINUTE) / SECOND); - const milliseconds = Math.floor(time % SECOND); - - return { - days, - hours, - minutes, - seconds, - milliseconds, - }; -} - -export function parseFormat(format: string, timeData: TimeData): string { - const { days } = timeData; - let { hours, minutes, seconds, milliseconds } = timeData; +export function parseFormat(format: string, currentTime: CurrentTime): string { + const { days } = currentTime; + let { hours, minutes, seconds, milliseconds } = currentTime; if (format.indexOf('DD') === -1) { hours += days * 24;