提交 40008bc2 编写于 作者: V Vben

refactor: refactor CountTo component

上级 00fca0fe
## Wip
### ✨ Refactor
- `CountTo`组件重构
### ✨ Features
- `radioButtonGroup` 支持`boolean`
- `useModalInner` 新增 `redoModalHeight`用于在 Modal 内部重设`Modal`高度
- `useECharts` 新增`getInstance`用于获取`echart`实例
......@@ -12,7 +18,7 @@
- `BasicTable`新增`updateTableDataRecord`方法用于更新指定行数据
- `useModal`新增`closeModal`方法用于关闭`Modal`
## Bug Fixes
### 🐛 Bug Fixes
- 修复`redoModalHeight`不能减小高度的问题
- 修复 `BasicForm`设置 schemas 数据不生效的问题
......
......@@ -71,7 +71,8 @@
});
onUnmounted(() => {
unref(wrapRef) && document.body.removeChild(el);
const el = unref(wrapRef);
el && document.body.removeChild(el);
});
function handleAction(item: ContextMenuItem, e: MouseEvent) {
......@@ -118,8 +119,10 @@
});
}
return () => {
if (!unref(showRef)) {
return null;
}
const { items } = props;
if (!unref(showRef)) return null;
return (
<Menu
inlineIndent={12}
......
// Transform vue-count-to to support vue3 version
import { withInstall } from '/@/utils';
import countTo from './src/CountTo.vue';
import { createAsyncComponent } from '/@/utils/factory/createAsyncComponent';
export const CountTo = createAsyncComponent(() => import('./src/CountTo.vue'));
export const CountTo = withInstall(countTo);
<template>
<span :style="{ color: color }">
{{ displayValue }}
<span :style="{ color }">
{{ value }}
</span>
</template>
<script lang="ts">
import { defineComponent, reactive, computed, watch, onMounted, unref, toRef } from 'vue';
import { countToProps } from './props';
import { defineComponent, ref, computed, watchEffect, unref, onMounted, watch } from 'vue';
import { useTransition, TransitionPresets } from '@vueuse/core';
import { isNumber } from '/@/utils/is';
const props = {
startVal: { type: Number, default: 0 },
endVal: { type: Number, default: 2021 },
duration: { type: Number, default: 1500 },
autoplay: { type: Boolean, default: true },
decimals: {
type: Number,
default: 0,
validator(value: number) {
return value >= 0;
},
},
prefix: { type: String, default: '' },
suffix: { type: String, default: '' },
separator: { type: String, default: ',' },
decimal: { type: String, default: '.' },
/**
* font color
*/
color: { type: String },
/**
* Turn on digital animation
*/
useEasing: { type: Boolean, default: true },
/**
* Digital animation
*/
transition: { type: String, default: 'linear' },
};
export default defineComponent({
name: 'CountTo',
props: countToProps,
emits: ['mounted', 'callback'],
props,
emits: ['onStarted', 'onFinished'],
setup(props, { emit }) {
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;
color: any;
}>({
localStartVal: props.startVal,
displayValue: formatNumber(props.startVal),
printVal: null,
paused: false,
localDuration: props.duration,
startTime: null,
timestamp: null,
remaining: null,
rAF: null,
color: null,
});
const source = ref(props.startVal);
const disabled = ref(false);
let outputValue = useTransition(source);
onMounted(() => {
if (props.autoplay) {
start();
}
emit('mounted');
});
const value = computed(() => formatNumber(unref(outputValue)));
const getCountDown = computed(() => {
return props.startVal > props.endVal;
watchEffect(() => {
source.value = props.startVal;
});
watch([() => props.startVal, () => props.endVal], () => {
......@@ -53,93 +59,42 @@
}
});
function start() {
const { startVal, duration, color } = props;
state.localStartVal = startVal;
state.startTime = null;
state.localDuration = duration;
state.color = color;
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);
}
onMounted(() => {
props.autoplay && start();
});
function resume() {
state.startTime = null;
state.localDuration = +(state.remaining as number);
state.localStartVal = +(state.printVal as number);
requestAnimationFrame(count);
function start() {
run();
source.value = props.endVal;
}
function reset() {
state.startTime = null;
cancelAnimationFrame(state.rAF);
state.displayValue = formatNumber(props.startVal);
source.value = props.startVal;
run();
}
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 run() {
outputValue = useTransition(source, {
disabled,
duration: props.duration,
onFinished: () => emit('onFinished'),
onStarted: () => emit('onStarted'),
...(props.useEasing ? { transition: TransitionPresets[props.transition] } : {}),
});
}
function formatNumber(num: number | string) {
if (!num) {
return '';
}
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)) {
......@@ -149,14 +104,7 @@
return prefix + x1 + x2 + suffix;
}
return {
count,
reset,
resume,
start,
pauseResume,
displayValue: toRef(state, 'displayValue'),
};
return { value, start, reset };
},
});
</script>
import { PropType } from 'vue';
import { propTypes } from '/@/utils/propTypes';
export const countToProps = {
startVal: propTypes.number.def(0),
endVal: propTypes.number.def(2020),
duration: propTypes.number.def(1300),
autoplay: propTypes.bool.def(true),
decimals: {
type: Number as PropType<number>,
required: false,
default: 0,
validator(value: number) {
return value >= 0;
},
},
color: {
type: String as PropType<string>,
require: false,
},
decimal: propTypes.string.def('.'),
separator: propTypes.string.def(','),
prefix: propTypes.string.def(''),
suffix: propTypes.string.def(''),
useEasing: propTypes.bool.def(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;
},
},
};
......@@ -20,7 +20,7 @@
type Options = Cropper.Options;
const defaultOptions: Cropper.Options = {
const defaultOptions: Options = {
aspectRatio: 16 / 9,
zoomable: true,
zoomOnTouch: true,
......@@ -42,6 +42,7 @@
movable: true,
rotatable: true,
};
export default defineComponent({
name: 'CropperImage',
props: {
......@@ -108,9 +109,9 @@
let imgInfo = cropper.value.getData();
cropper.value.getCroppedCanvas().toBlob((blob) => {
let fileReader: FileReader = new FileReader();
fileReader.onloadend = (e: any) => {
fileReader.onloadend = (e) => {
ctx.emit('cropperedInfo', {
imgBase64: e.target.result,
imgBase64: e.target?.result ?? '',
imgInfo,
});
};
......
......@@ -1252,21 +1252,21 @@
"@intlify/runtime" "9.1.6"
"@intlify/shared" "9.1.6"
"@logicflow/core@^0.4.11":
version "0.4.11"
resolved "https://registry.yarnpkg.com/@logicflow/core/-/core-0.4.11.tgz#3c617e5cddb47e7052d62fee56ba77ab45b1cd25"
integrity sha512-FlErJRyKw+XzyT0/0hha8Dwsiok9Cri2ZS2/SDmqLdUK6I3rD6LpmVabj8LjYH4IWb0fOYSfgGhY4oWQAKqa9g==
"@logicflow/core@^0.4.13":
version "0.4.13"
resolved "https://registry.npmjs.org/@logicflow/core/-/core-0.4.13.tgz#69d1e7a30b5e545ada3a2e980059f3e6f6923f15"
integrity sha512-xOLz8RO6ldAT5H9Q2Ewt9d7z146B54TUom5EXzJ/jx/s1Phy24vP8tAGu6LuoTEitgNHTRQq7WxvH9NqnpxCpg==
dependencies:
"@types/mousetrap" "^1.6.4"
mousetrap "^1.6.5"
preact "^10.4.8"
"@logicflow/extension@^0.4.12":
version "0.4.12"
resolved "https://registry.yarnpkg.com/@logicflow/extension/-/extension-0.4.12.tgz#be69e8ebbcffee6bb0f07778f2126ad98f93f64a"
integrity sha512-fD0bXxYIEo1d047A3PXkAVMH6vM5y8AAIfLxnXxdMJGOVLH44iWCO6eNW8bvnoab7aSmhj2MWMgY3op5XVZh1Q==
"@logicflow/extension@^0.4.13":
version "0.4.13"
resolved "https://registry.npmjs.org/@logicflow/extension/-/extension-0.4.13.tgz#b1c87b5458345414cc6c5fb813511e62db4acfa7"
integrity sha512-DAfgO9A5VrJ4oXruTYGgmDGvZAIaT2kLAlTE+luyg4eld6YsgwWXqXazJWCd9ObdAJkLYCf7lU27hZsDNqqbrg==
dependencies:
"@logicflow/core" "^0.4.11"
"@logicflow/core" "^0.4.13"
ids "^1.0.0"
preact "^10.4.8"
......@@ -2033,25 +2033,25 @@
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.0.11.tgz#20d22dd0da7d358bb21c17f9bde8628152642c77"
integrity sha512-b+zB8A2so8eCE0JsxjL24J7vdGl8rzPQ09hZNhystm+KqSbKcAej1A+Hbva1rCMmTTqA+hFnUSDc5kouEo0JzA==
"@vueuse/core@^5.0.1":
version "5.0.1"
resolved "https://registry.npmjs.org/@vueuse/core/-/core-5.0.1.tgz#94bbb6c71d95b79efbdb24111915775e61723f1b"
integrity sha512-hzcyYNvW1p9ZEwm+oBaWrHgGx6S93pJBiXLZUj2pgCNiJZjaedoePT9xzesi1SBxeKcYxwToaTISLeKdE4VKeg==
"@vueuse/core@^5.0.2":
version "5.0.2"
resolved "https://registry.npmjs.org/@vueuse/core/-/core-5.0.2.tgz#302389f620c0d4b51fdf157012d9b5b522b605e7"
integrity sha512-Sp9+7AL4Cg3Tx6I55WoH7zICGRlp6ZUF9NW3EU8SZTkryHm0afAjFfASMwlfV030JFeh45BdqafDOrenVmM9Cw==
dependencies:
"@vueuse/shared" "5.0.1"
"@vueuse/shared" "5.0.2"
vue-demi "*"
"@vueuse/shared@5.0.1":
version "5.0.1"
resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-5.0.1.tgz#3b6607ffc9e19b322c39be8a2f6b584d203a7c5e"
integrity sha512-/+kRII9chn45PhFfRuPVbSQApJHhhqXFhPrWjnYKckMfQE9ZOuNMb1bmQnDTqzuNkoS/ENeHBMq0rnV/cfz/3Q==
"@vueuse/shared@5.0.2":
version "5.0.2"
resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-5.0.2.tgz#274c2bf163d25eb7fd2fc51f23088a2b7f060594"
integrity sha512-S1hRRmEdipjTD4DbXgPdw4ZZYebU/nDi75vNP3Ibpa1irW3NUNUKOT/TWnwRHLQvXquUtdvalhI8D9Db+czZJg==
dependencies:
vue-demi "*"
"@windicss/plugin-utils@1.0.2":
version "1.0.2"
resolved "https://registry.npmjs.org/@windicss/plugin-utils/-/plugin-utils-1.0.2.tgz#c34d6498058d5f4291805027d2ef6e34638a572a"
integrity sha512-W9fZoPNsD3NMVyqzt9eNb1DNp9p4oy7EscCfGVIg1KBxAC8S+AnXtkaR/rad09y+aqzbILKNfzDKdimDR2FA9g==
"@windicss/plugin-utils@1.0.3":
version "1.0.3"
resolved "https://registry.npmjs.org/@windicss/plugin-utils/-/plugin-utils-1.0.3.tgz#04d039ef56b58180079df3f9b3bd8a21a57368d3"
integrity sha512-SBYjmWBO+dOqxJgyyOAETOuMdcugvVgZYQc3rb7KtcTW5u9UkFXtiuGdoq8cWyFpSkn46gmjCb4WNbY3kEIVnQ==
dependencies:
"@antfu/utils" "^0.1.6"
debug "^4.3.2"
......@@ -4050,13 +4050,13 @@ duplexer3@^0.1.4:
resolved "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
echarts@^5.1.1:
version "5.1.1"
resolved "https://registry.npmjs.org/echarts/-/echarts-5.1.1.tgz#b186f162f017c555cfd67b12ede6762bdc3ddfda"
integrity sha512-b3nP8M9XwZM2jISuA+fP0EuJv8lcfgWrinel185Npy8bE/UhXTDIPJcqgQOCWdvk0c5CeT6Dsm1xBjmJXAGlxQ==
echarts@^5.1.2:
version "5.1.2"
resolved "https://registry.npmjs.org/echarts/-/echarts-5.1.2.tgz#aa1ab0cef5b74fa2f7c620261a5f286893d30fd1"
integrity sha512-okUhO4sw22vwZp+rTPNjd/bvTdpug4K4sHNHyrV8NdAncIX9/AarlolFqtJCAYKGFYhUBNjIWu1EznFrSWTFxg==
dependencies:
tslib "2.0.3"
zrender "5.1.0"
zrender "5.1.1"
ecstatic@^3.3.2:
version "3.3.2"
......@@ -10573,10 +10573,10 @@ vite-plugin-imagemin@^0.3.2:
imagemin-svgo "^8.0.0"
imagemin-webp "^6.0.0"
vite-plugin-mock@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/vite-plugin-mock/-/vite-plugin-mock-2.7.0.tgz#21aec0397e29d013c87d765c56d177728d4288b4"
integrity sha512-hB3MbnQlrmqGOigbPB+UsUQ/ZjTisj75FprJ7IDw8pDYQjWmHC7AtmDOHdzpGYPKEEX1mz7UhGJ93LLarPqJNg==
vite-plugin-mock@^2.7.1:
version "2.7.1"
resolved "https://registry.npmjs.org/vite-plugin-mock/-/vite-plugin-mock-2.7.1.tgz#c7d25277f7b88158cd3927c1abee7c7721ed92d3"
integrity sha512-UnYcb4UZrpe5fHBNFNEJQetnR32+XxrduTYhyDQTtXmaJ9Yy+JuBfIT6Mueyf7MGPe8T6hNgIEYaMLSUD5+nWA==
dependencies:
"@rollup/plugin-node-resolve" "^11.2.1"
"@types/mockjs" "^1.0.3"
......@@ -10647,12 +10647,12 @@ vite-plugin-theme@^0.8.1:
esbuild-plugin-alias "^0.1.2"
tinycolor2 "^1.4.2"
vite-plugin-windicss@^1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/vite-plugin-windicss/-/vite-plugin-windicss-1.0.2.tgz#0d0fd1ff36dc81d348be755e59a8ee471941095c"
integrity sha512-iTmkxm8Yp+ZCFWLOs//9q3d4hYaBVDlkRGLzNBUNvRW9AQFVea57ZPhglMm9xOt1nW/O68n5Rkg4/In8rrEjHQ==
vite-plugin-windicss@^1.0.3:
version "1.0.3"
resolved "https://registry.npmjs.org/vite-plugin-windicss/-/vite-plugin-windicss-1.0.3.tgz#bd45cfee13777e7b57c37a257ebcb7e73fee94ab"
integrity sha512-y9pudcMajdI88PTs49qGftlfAvsLUUhK2Eig+xn5sgxPCbAc3Rj5phXJkRzGDqfmEzGwbpF6JwjmiGmZkm8V+g==
dependencies:
"@windicss/plugin-utils" "1.0.2"
"@windicss/plugin-utils" "1.0.3"
chalk "^4.1.1"
debug "^4.3.2"
windicss "^3.1.3"
......@@ -11321,10 +11321,10 @@ yocto-queue@^0.1.0:
resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
zrender@5.1.0:
version "5.1.0"
resolved "https://registry.npmjs.org/zrender/-/zrender-5.1.0.tgz#b6a84c3aa7ccc6642ee0519901ca4c0835c4d85e"
integrity sha512-c+8VRx52ycbmqwHeHLlo/BAfIHBl/JZNLM6cfDQFgzIH05yb+f5J9F/fbRsP+zGc8dW9XHuhdt8/iqukgMZSeg==
zrender@5.1.1:
version "5.1.1"
resolved "https://registry.npmjs.org/zrender/-/zrender-5.1.1.tgz#0515f4f8cc0f4742f02a6b8819550a6d13d64c5c"
integrity sha512-oeWlmUZPQdS9f5hK4pV21tHPqA3wgQ7CkKkw7l0CCBgWlJ/FP+lRgLFtUBW6yam4JX8y9CdHJo1o587VVrbcoQ==
dependencies:
tslib "2.0.3"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册