写了两个组件,一个是DigitalFlop.vue,一个是DigitalItem.vue
DigitalFlop.vue 的代码如下:
<template>
<div class="digital-flop-component">
<DigitalItem
v-for="(item, index) in integerDigitalArray"
:key="getItemKey(index)"
:data="item"
:animation="animation"
></DigitalItem>
<DigitalItem
v-for="(item, index) in decimalDigitalArray"
:key="index"
:data="item"
:isDecimalPlace="true"
:animation="animation"
></DigitalItem>
</div>
</template>
<script setup lang="ts">
/**
* @Description: 数字翻牌器组件
* @version 1.0.0 2022-06-05 22:10:42
*/
import { ref, watch, nextTick, onMounted } from "vue";
import DigitalItem from "./DigitalItem.vue";
interface Props {
value: number;
minLength?: number | undefined;
maxLength?: number | undefined;
// 小数位数
decimalPlaceNumber?: number;
// 是否显示千分位
isShowSeparator?: boolean;
// 是否添加动画效果
animation?: boolean;
// 整数数字牌样式
integerCardStyle?: any;
// 小数位数字牌样式
decimalPlaceCardStyle?: any;
}
const props = withDefaults(defineProps<Props>(), {
value: 0,
minLength: 4,
isShowSeparator: false,
animation: true,
decimalPlaceNumber: 2
});
// 整数数组
const integerDigitalArray = ref<string[]>([]);
// 小数数组
const decimalDigitalArray = ref<string[]>([]);
watch(
() => props.value,
() => {
initDigitalData(props.value);
},
{ immediate: true }
);
/**
* 设置整数数组
* @param digitalValue
*/
function initDigitalData(digitalValue: number) {
let integerArray = [];
// 显示小数位
if (props.decimalPlaceNumber > 0) {
const value = digitalValue.toFixed(props.decimalPlaceNumber);
const index = value.indexOf(".");
decimalDigitalArray.value = value.substring(index + 1).split("");
integerArray = value.substring(0, index).split("");
} else {
decimalDigitalArray.value = [];
integerArray = digitalValue.toString().split("");
}
const addZero = (array: string[], minLength: number) => {
if (array.length < minLength) {
array.unshift("0");
addZero(array, minLength);
}
};
if (props.minLength) {
addZero(integerArray, props.minLength);
}
if (props.maxLength && integerArray.length > props.maxLength) {
console.error(
`传入的数字${digitalValue}已经超过最大长度${props.maxLength}`
);
}
// 添加千分位
if (props.isShowSeparator) {
integerArray = addSeparator(integerArray);
}
integerDigitalArray.value = integerArray;
}
/**
* 添加千分号
* @param array
*/
function addSeparator(array: Array<string>) {
const dataArray = array.reverse();
const separatorArray = [];
while (dataArray.length) {
separatorArray.push(dataArray.splice(0, 3).join(""));
}
return separatorArray.join(",").split("").reverse();
}
// 设置关键字,从小数位开始向左为1,避免出现数字变大时的显示问题
function getItemKey(index: number) {
return integerDigitalArray.value.length - index;
}
</script>
<style lang="scss" scoped>
.digital-flop-component {
display: flex;
align-items: flex-end;
flex-wrap: nowrap;
.digital-item-component {
margin-right: 5px;
}
.digital-item-component:last-child {
margin-right: 0;
}
}
</style>
DigitalItem.vue的代码如下:
<template>
<div class="digital-item-component">
<div
v-if="isNumberString"
class="box-item"
:class="{ 'decimal-place-box-item': isDecimalPlace }"
>
<div class="number-text-container">
<!--动态切换效果-->
<template v-if="animation">
<div
v-for="num in 10"
:key="num"
class="number-value"
:style="numberDynamicStyle"
>
{{ num - 1 }}
</div>
</template>
<div class="number-value">{{ data }}</div>
</div>
</div>
<div class="comma-item" v-else>{{ data }}</div>
</div>
</template>
<script setup lang="ts">
import { computed } from "vue";
interface Props {
data: string;
// 是否小数位
isDecimalPlace?: boolean;
// 是否添加动画效果
animation?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
data: "0",
animation: true,
isDecimalPlace: false
});
const isNumberString = computed(() => {
const numberValue = Number(props.data);
return !isNaN(numberValue);
});
// 数字动态样式
const numberDynamicStyle = computed(() => {
let numberValue = Number(props.data);
if (isNaN(numberValue)) {
numberValue = 0;
}
return {
transform: `translate(0, -${numberValue * 100}%)`,
transition: "transform 1s ease-in-out"
};
});
</script>
<style lang="scss">
// 数字翻牌器样式变量
:root {
--da-digital-item-width: 40px;
--da-digital-item-height: 60px;
--da-digital-item-font-size: 40px;
--da-digital-item-decimal-place-width: 28px;
--da-digital-item-decimal-place-height: 40px;
--da-digital-item-decimal-place-font-size: 28px;
--da-digital-item-bg-color: #409eff;
}
</style>
<style lang="scss" scoped>
.digital-item-component {
.box-item {
width: var(--da-digital-item-width);
height: var(--da-digital-item-height);
font-size: var(--da-digital-item-font-size);
font-weight: 500;
line-height: 1;
border-radius: 4px;
color: #fff;
background-color: var(--da-digital-item-bg-color);
position: relative;
overflow: hidden;
.number-text-container {
display: flex;
flex-direction: column;
flex-wrap: wrap;
.number-value {
flex: none;
width: var(--da-digital-item-width);
height: var(--da-digital-item-height);
display: flex;
align-items: center;
justify-content: center;
}
}
}
.comma-item {
padding: 0 5px;
height: 100%;
text-align: center;
font-size: 30px;
font-weight: bold;
color: #000;
}
.decimal-place-box-item {
width: var(--da-digital-item-decimal-place-width);
height: var(--da-digital-item-decimal-place-height);
.number-text-container {
.number-value {
width: var(--da-digital-item-decimal-place-width);
height: var(--da-digital-item-decimal-place-height);
font-size: var(--da-digital-item-decimal-place-font-size);
}
}
}
}
</style>
用法:
HTML template部分
<DigitalFlop class="customize-digital-flop" :value="value"></DigitalFlop>
<el-button type="primary" @click="changeNumber">change number</el-button>
<script setup lang="ts"> 部分
const value = ref(0);
function changeNumber() {
if (moneyValue.value === 5792.72) {
moneyValue.value = 12305.34;
} else {
moneyValue.value = 5792.72;
}
}
样式部分(可自定义样式)
<style lang="scss" scoped>
.customize-digital-flop {
--da-digital-item-width: 30px;
--da-digital-item-height: 40px;
--da-digital-item-font-size: 30px;
--da-digital-item-decimal-place-width: 24px;
--da-digital-item-decimal-place-height: 30px;
--da-digital-item-decimal-place-font-size: 24px;
--da-digital-item-bg-color: #07368a;
}
</style>
效果如下:
组件样式风格没有细致去修改,大家可以发挥自己特长继续优化哈。