mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-27 15:41:32 +08:00
feat(analysis): add analysis page
This commit is contained in:
2
src/components/CountTo/index.ts
Normal file
2
src/components/CountTo/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
// 对vue-count-to进行改造成支持vue3版本
|
||||
export { default as CountTo } from './src/index.vue';
|
159
src/components/CountTo/src/index.vue
Normal file
159
src/components/CountTo/src/index.vue
Normal file
@@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<span>
|
||||
{{ displayValue }}
|
||||
</span>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, computed, watch, onMounted, unref, toRef } from 'vue';
|
||||
|
||||
import { countToProps } from './props';
|
||||
import { useRaf } from '/@/hooks/event/useRaf';
|
||||
import { isNumber } from '/@/utils/is';
|
||||
export default defineComponent({
|
||||
name: 'CountTo',
|
||||
props: countToProps,
|
||||
emits: ['mounted', 'callback'],
|
||||
setup(props, { emit }) {
|
||||
const { requestAnimationFrame, cancelAnimationFrame } = useRaf();
|
||||
|
||||
const state = reactive<{
|
||||
localStartVal: number;
|
||||
printVal: number | null;
|
||||
displayValue: string;
|
||||
paused: boolean;
|
||||
localDuration: number | null;
|
||||
startTime: number | null;
|
||||
timestamp: number | null;
|
||||
rAF: any;
|
||||
remaining: number | null;
|
||||
}>({
|
||||
localStartVal: props.startVal,
|
||||
displayValue: formatNumber(props.startVal),
|
||||
printVal: null,
|
||||
paused: false,
|
||||
localDuration: props.duration,
|
||||
startTime: null,
|
||||
timestamp: null,
|
||||
remaining: null,
|
||||
rAF: null,
|
||||
});
|
||||
onMounted(() => {
|
||||
if (props.autoplay) {
|
||||
start();
|
||||
}
|
||||
emit('mounted');
|
||||
});
|
||||
const getCountDown = computed(() => {
|
||||
return props.startVal > props.endVal;
|
||||
});
|
||||
|
||||
watch([() => props.startVal, () => props.endVal], () => {
|
||||
if (props.autoplay) {
|
||||
start();
|
||||
}
|
||||
});
|
||||
|
||||
function start() {
|
||||
const { startVal, duration } = props;
|
||||
state.localStartVal = startVal;
|
||||
state.startTime = null;
|
||||
state.localDuration = duration;
|
||||
state.paused = false;
|
||||
state.rAF = requestAnimationFrame(count);
|
||||
}
|
||||
function pauseResume() {
|
||||
if (state.paused) {
|
||||
resume();
|
||||
state.paused = false;
|
||||
} else {
|
||||
pause();
|
||||
state.paused = true;
|
||||
}
|
||||
}
|
||||
function pause() {
|
||||
cancelAnimationFrame(state.rAF);
|
||||
}
|
||||
|
||||
function resume() {
|
||||
state.startTime = null;
|
||||
state.localDuration = +(state.remaining as number);
|
||||
state.localStartVal = +(state.printVal as number);
|
||||
requestAnimationFrame(count);
|
||||
}
|
||||
|
||||
function reset() {
|
||||
state.startTime = null;
|
||||
cancelAnimationFrame(state.rAF);
|
||||
state.displayValue = formatNumber(props.startVal);
|
||||
}
|
||||
|
||||
function count(timestamp: number) {
|
||||
const { useEasing, easingFn, endVal } = props;
|
||||
if (!state.startTime) state.startTime = timestamp;
|
||||
state.timestamp = timestamp;
|
||||
const progress = timestamp - state.startTime;
|
||||
state.remaining = (state.localDuration as number) - progress;
|
||||
if (useEasing) {
|
||||
if (unref(getCountDown)) {
|
||||
state.printVal =
|
||||
state.localStartVal -
|
||||
easingFn(progress, 0, state.localStartVal - endVal, state.localDuration as number);
|
||||
} else {
|
||||
state.printVal = easingFn(
|
||||
progress,
|
||||
state.localStartVal,
|
||||
endVal - state.localStartVal,
|
||||
state.localDuration as number
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (unref(getCountDown)) {
|
||||
state.printVal =
|
||||
state.localStartVal -
|
||||
(state.localStartVal - endVal) * (progress / (state.localDuration as number));
|
||||
} else {
|
||||
state.printVal =
|
||||
state.localStartVal +
|
||||
(endVal - state.localStartVal) * (progress / (state.localDuration as number));
|
||||
}
|
||||
}
|
||||
if (unref(getCountDown)) {
|
||||
state.printVal = state.printVal < endVal ? endVal : state.printVal;
|
||||
} else {
|
||||
state.printVal = state.printVal > endVal ? endVal : state.printVal;
|
||||
}
|
||||
state.displayValue = formatNumber(state.printVal);
|
||||
if (progress < (state.localDuration as number)) {
|
||||
state.rAF = requestAnimationFrame(count);
|
||||
} else {
|
||||
emit('callback');
|
||||
}
|
||||
}
|
||||
|
||||
function formatNumber(num: number | string) {
|
||||
const { decimals, decimal, separator, suffix, prefix } = props;
|
||||
num = Number(num).toFixed(decimals);
|
||||
num += '';
|
||||
const x = num.split('.');
|
||||
let x1 = x[0];
|
||||
const x2 = x.length > 1 ? decimal + x[1] : '';
|
||||
const rgx = /(\d+)(\d{3})/;
|
||||
if (separator && !isNumber(separator)) {
|
||||
while (rgx.test(x1)) {
|
||||
x1 = x1.replace(rgx, '$1' + separator + '$2');
|
||||
}
|
||||
}
|
||||
return prefix + x1 + x2 + suffix;
|
||||
}
|
||||
|
||||
return {
|
||||
count,
|
||||
reset,
|
||||
resume,
|
||||
start,
|
||||
pauseResume,
|
||||
displayValue: toRef(state, 'displayValue'),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
62
src/components/CountTo/src/props.ts
Normal file
62
src/components/CountTo/src/props.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { PropType } from 'vue';
|
||||
export const countToProps = {
|
||||
startVal: {
|
||||
type: Number as PropType<number>,
|
||||
required: false,
|
||||
default: 0,
|
||||
},
|
||||
endVal: {
|
||||
type: Number as PropType<number>,
|
||||
required: false,
|
||||
default: 2017,
|
||||
},
|
||||
duration: {
|
||||
type: Number as PropType<number>,
|
||||
required: false,
|
||||
default: 3000,
|
||||
},
|
||||
autoplay: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
decimals: {
|
||||
type: Number as PropType<number>,
|
||||
required: false,
|
||||
default: 0,
|
||||
validator(value: number) {
|
||||
return value >= 0;
|
||||
},
|
||||
},
|
||||
decimal: {
|
||||
type: String as PropType<string>,
|
||||
required: false,
|
||||
default: '.',
|
||||
},
|
||||
separator: {
|
||||
type: String as PropType<string>,
|
||||
required: false,
|
||||
default: ',',
|
||||
},
|
||||
prefix: {
|
||||
type: String as PropType<string>,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
suffix: {
|
||||
type: String as PropType<string>,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
useEasing: {
|
||||
type: Boolean as PropType<boolean>,
|
||||
required: false,
|
||||
default: true,
|
||||
},
|
||||
easingFn: {
|
||||
type: Function as PropType<(t: number, b: number, c: number, d: number) => number>,
|
||||
default(t: number, b: number, c: number, d: number) {
|
||||
return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b;
|
||||
},
|
||||
},
|
||||
};
|
Reference in New Issue
Block a user