mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
chore(CountDown): extract useCountDown
This commit is contained in:
parent
38334b4158
commit
8e5c8f2f89
@ -134,26 +134,27 @@ export default {
|
|||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
| Event | Description | Arguments |
|
| Event | Description | Arguments |
|
||||||
| --------------- | ---------------------------------- | -------------------- |
|
| --- | --- | --- |
|
||||||
| finish | Triggered when count down finished | - |
|
| finish | Triggered when count down finished | - |
|
||||||
| change `v2.4.4` | Triggered when count down changed | _timeData: TimeData_ |
|
| change `v2.4.4` | Triggered when count down changed | _currentTime: CurrentTime_ |
|
||||||
|
|
||||||
### Slots
|
### Slots
|
||||||
|
|
||||||
| Name | Description | SlotProps |
|
| Name | Description | SlotProps |
|
||||||
| ------- | -------------- | -------------------- |
|
| ------- | -------------- | -------------------------- |
|
||||||
| default | Custom Content | _timeData: TimeData_ |
|
| default | Custom Content | _currentTime: CurrentTime_ |
|
||||||
|
|
||||||
### TimeData Structure
|
### TimeData Structure
|
||||||
|
|
||||||
| Name | Description | Type |
|
| Name | Description | Type |
|
||||||
| ------------ | ------------------- | -------- |
|
| ------------ | ----------------------------- | -------- |
|
||||||
| days | Remain days | _number_ |
|
| total | Total time, unit milliseconds | _number_ |
|
||||||
| hours | Remain hours | _number_ |
|
| days | Remain days | _number_ |
|
||||||
| minutes | Remain minutes | _number_ |
|
| hours | Remain hours | _number_ |
|
||||||
| seconds | Remain seconds | _number_ |
|
| minutes | Remain minutes | _number_ |
|
||||||
| milliseconds | Remain milliseconds | _number_ |
|
| seconds | Remain seconds | _number_ |
|
||||||
|
| milliseconds | Remain milliseconds | _number_ |
|
||||||
|
|
||||||
### Methods
|
### Methods
|
||||||
|
|
||||||
|
@ -144,26 +144,27 @@ export default {
|
|||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
| 事件名 | 说明 | 回调参数 |
|
| 事件名 | 说明 | 回调参数 |
|
||||||
| --------------- | ---------------- | -------------------- |
|
| --------------- | ---------------- | -------------------------- |
|
||||||
| finish | 倒计时结束时触发 | - |
|
| finish | 倒计时结束时触发 | - |
|
||||||
| change `v2.4.4` | 倒计时变化时触发 | _timeData: TimeData_ |
|
| change `v2.4.4` | 倒计时变化时触发 | _currentTime: CurrentTime_ |
|
||||||
|
|
||||||
### Slots
|
### Slots
|
||||||
|
|
||||||
| 名称 | 说明 | SlotProps |
|
| 名称 | 说明 | SlotProps |
|
||||||
| ------- | ---------- | -------------------- |
|
| ------- | ---------- | -------------------------- |
|
||||||
| default | 自定义内容 | _timeData: TimeData_ |
|
| default | 自定义内容 | _currentTime: CurrentTime_ |
|
||||||
|
|
||||||
### TimeData 格式
|
### CurrentTime 格式
|
||||||
|
|
||||||
| 名称 | 说明 | 类型 |
|
| 名称 | 说明 | 类型 |
|
||||||
| ------------ | -------- | -------- |
|
| ------------ | ---------------------- | -------- |
|
||||||
| days | 剩余天数 | _number_ |
|
| total | 剩余总时间(单位毫秒) | _number_ |
|
||||||
| hours | 剩余小时 | _number_ |
|
| days | 剩余天数 | _number_ |
|
||||||
| minutes | 剩余分钟 | _number_ |
|
| hours | 剩余小时 | _number_ |
|
||||||
| seconds | 剩余秒数 | _number_ |
|
| minutes | 剩余分钟 | _number_ |
|
||||||
| milliseconds | 剩余毫秒 | _number_ |
|
| seconds | 剩余秒数 | _number_ |
|
||||||
|
| milliseconds | 剩余毫秒 | _number_ |
|
||||||
|
|
||||||
### 方法
|
### 方法
|
||||||
|
|
||||||
|
@ -1,18 +1,12 @@
|
|||||||
import {
|
import { watch, computed } from 'vue';
|
||||||
ref,
|
|
||||||
watch,
|
|
||||||
computed,
|
|
||||||
onActivated,
|
|
||||||
onDeactivated,
|
|
||||||
onBeforeUnmount,
|
|
||||||
} from 'vue';
|
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import { raf, cancelRaf, createNamespace } from '../utils';
|
import { createNamespace } from '../utils';
|
||||||
import { isSameSecond, parseTimeData, parseFormat } from './utils';
|
import { parseFormat } from './utils';
|
||||||
|
|
||||||
// Composition
|
// Composition
|
||||||
import { useExpose } from '../composition/use-expose';
|
import { useExpose } from '../composition/use-expose';
|
||||||
|
import { useCountDown } from './use-count-down';
|
||||||
|
|
||||||
const [createComponent, bem] = createNamespace('count-down');
|
const [createComponent, bem] = createNamespace('count-down');
|
||||||
|
|
||||||
@ -36,118 +30,37 @@ export default createComponent({
|
|||||||
emits: ['change', 'finish'],
|
emits: ['change', 'finish'],
|
||||||
|
|
||||||
setup(props, { emit, slots }) {
|
setup(props, { emit, slots }) {
|
||||||
let rafId;
|
const { start, pause, reset, current } = useCountDown({
|
||||||
let endTime;
|
time: +props.time,
|
||||||
let counting;
|
millisecond: props.millisecond,
|
||||||
let keepAlived;
|
onChange(current) {
|
||||||
|
emit('change', current);
|
||||||
const remain = ref(0);
|
},
|
||||||
const timeData = computed(() => parseTimeData(remain.value));
|
onFinish() {
|
||||||
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();
|
|
||||||
emit('finish');
|
emit('finish');
|
||||||
}
|
},
|
||||||
};
|
});
|
||||||
|
|
||||||
const microTick = () => {
|
const timeText = computed(() => parseFormat(props.format, current.value));
|
||||||
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 resetTime = () => {
|
||||||
|
reset(+props.time);
|
||||||
if (props.autoStart) {
|
if (props.autoStart) {
|
||||||
start();
|
start();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(() => props.time, reset, { immediate: true });
|
watch(() => props.time, resetTime, { immediate: true });
|
||||||
|
|
||||||
onActivated(() => {
|
|
||||||
if (keepAlived) {
|
|
||||||
counting = true;
|
|
||||||
keepAlived = false;
|
|
||||||
tick();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
onDeactivated(() => {
|
|
||||||
if (counting) {
|
|
||||||
pause();
|
|
||||||
keepAlived = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
onBeforeUnmount(pause);
|
|
||||||
|
|
||||||
useExpose({
|
useExpose({
|
||||||
start,
|
start,
|
||||||
reset,
|
|
||||||
pause,
|
pause,
|
||||||
|
reset: resetTime,
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<div class={bem()}>
|
<div class={bem()}>
|
||||||
{slots.default ? slots.default(timeData.value) : timeText.value}
|
{slots.default ? slots.default(current.value) : timeText.value}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
149
src/count-down/use-count-down.ts
Normal file
149
src/count-down/use-count-down.ts
Normal file
@ -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,
|
||||||
|
};
|
||||||
|
}
|
@ -1,37 +1,9 @@
|
|||||||
import { padZero } from '../utils';
|
import { padZero } from '../utils';
|
||||||
|
import { CurrentTime } from './use-count-down';
|
||||||
|
|
||||||
export type TimeData = {
|
export function parseFormat(format: string, currentTime: CurrentTime): string {
|
||||||
days: number;
|
const { days } = currentTime;
|
||||||
hours: number;
|
let { hours, minutes, seconds, milliseconds } = currentTime;
|
||||||
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;
|
|
||||||
|
|
||||||
if (format.indexOf('DD') === -1) {
|
if (format.indexOf('DD') === -1) {
|
||||||
hours += days * 24;
|
hours += days * 24;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user