|
|
@@ -0,0 +1,223 @@
|
|
|
+<script setup lang="ts">
|
|
|
+interface Props {
|
|
|
+ width?: string
|
|
|
+ height?: string
|
|
|
+ textColor?: string
|
|
|
+ bgColor?: string
|
|
|
+ centerColor?: string
|
|
|
+ number?: number
|
|
|
+ waitingTime?: number
|
|
|
+ animationTime?: number
|
|
|
+ showSeparator?: boolean
|
|
|
+}
|
|
|
+
|
|
|
+const props = withDefaults(defineProps<Props>(), {
|
|
|
+ width: '40',
|
|
|
+ height: '60',
|
|
|
+ textColor: '#fff',
|
|
|
+ bgColor: '#f5ba1a',
|
|
|
+ centerColor: '#ffda4c',
|
|
|
+ number: 12367,
|
|
|
+ waitingTime: 4000,
|
|
|
+ animationTime: 1000,
|
|
|
+ showSeparator: false
|
|
|
+})
|
|
|
+
|
|
|
+const width = ref(props.width)
|
|
|
+const height = ref(props.height)
|
|
|
+const textColor = ref(props.textColor)
|
|
|
+const bgColor = ref(props.bgColor)
|
|
|
+const centerColor = ref(props.centerColor)
|
|
|
+const number = ref<number>(props.number)
|
|
|
+const waitingTime = ref(props.waitingTime)
|
|
|
+const animationTime = ref(props.animationTime)
|
|
|
+
|
|
|
+const list = ref<any>([])
|
|
|
+const numList = ref([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, '.'])
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ scroll()
|
|
|
+})
|
|
|
+
|
|
|
+const arrayChunk = (array: any, size: number) => {
|
|
|
+ let data = []
|
|
|
+ for (let i = 0; i < array.length; i += size) {
|
|
|
+ data.push(array.slice(i, i + size).reverse())
|
|
|
+ }
|
|
|
+ return data.reverse()
|
|
|
+}
|
|
|
+
|
|
|
+const getTop = (item: any) => {
|
|
|
+ let Hei = parseFloat(getComputedStyle(document.getElementById('dataNums')!).height)
|
|
|
+ item.forEach((e: any, index: any) => {
|
|
|
+ if (!e.length) {
|
|
|
+ setTimeout(() => {
|
|
|
+ e.top = e.num * Hei + Hei * 10
|
|
|
+ }, index * 300)
|
|
|
+ } else {
|
|
|
+ e.forEach((eItem: any, i: number) => {
|
|
|
+ setTimeout(() => {
|
|
|
+ eItem.top = eItem.num * Hei + Hei * 10
|
|
|
+ }, i * 300)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const scroll = () => {
|
|
|
+ list.value = number.value.toString().split('')
|
|
|
+ if (!props.showSeparator) {
|
|
|
+ let arr = <any>[]
|
|
|
+ list.value.map((item: any) => {
|
|
|
+ arr.push({ num: parseInt(item), top: 0 })
|
|
|
+ })
|
|
|
+ list.value = arr
|
|
|
+ getTop(list.value)
|
|
|
+ } else {
|
|
|
+ list.value = arrayChunk(number.value.toString().split('').reverse(), 3)
|
|
|
+ list.value.map((item: any, index: number) => {
|
|
|
+ let arr = <any>[]
|
|
|
+ item.map((item2: any, index2: number) => {
|
|
|
+ arr.push({ num: parseInt(item2), top: 0 })
|
|
|
+ })
|
|
|
+ list.value[index] = arr
|
|
|
+ })
|
|
|
+ getTop(list.value)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const setNumber = setInterval(() => {
|
|
|
+ number.value = Number(number.value) + 1000
|
|
|
+ scroll()
|
|
|
+}, waitingTime.value)
|
|
|
+
|
|
|
+onBeforeUnmount(() => {
|
|
|
+ if (setNumber) {
|
|
|
+ clearInterval(setNumber)
|
|
|
+ }
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="number">
|
|
|
+ <ul
|
|
|
+ id="dataNums"
|
|
|
+ :style="{
|
|
|
+ height: `${height}` + 'px'
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <template v-if="!props.showSeparator">
|
|
|
+ <li
|
|
|
+ v-for="(item, index) in list"
|
|
|
+ :key="index"
|
|
|
+ :style="{
|
|
|
+ width: width + 'px',
|
|
|
+ height: height + 'px'
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <div class="dataBoc">
|
|
|
+ <div
|
|
|
+ class="tt"
|
|
|
+ :style="{ transition: `all ${animationTime / 1000}s ease-in-out 0s`, top: '-' + item.top + 'px' }"
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ class="flex flex-nowrap value-item text-center items-start justify-center font-bold"
|
|
|
+ v-for="(item2, index2) in numList"
|
|
|
+ :key="index2"
|
|
|
+ :style="{
|
|
|
+ lineHeight: height + 'px',
|
|
|
+ fontSize: width + 'px'
|
|
|
+ }"
|
|
|
+ >{{ item2 }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <div v-for="(item, index) in list" :key="index">
|
|
|
+ <li
|
|
|
+ v-for="(item2, index) in item"
|
|
|
+ :key="index"
|
|
|
+ :style="{
|
|
|
+ width: `${width}` + 'px',
|
|
|
+ height: `${height}` + 'px'
|
|
|
+ }"
|
|
|
+ >
|
|
|
+ <div class="dataBoc">
|
|
|
+ <div
|
|
|
+ class="tt"
|
|
|
+ :style="{ transition: `all ${animationTime / 1000}s ease-in-out 0s`, top: '-' + item2.top + 'px' }"
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ class="flex flex-nowrap value-item text-center items-start justify-center font-bold"
|
|
|
+ v-for="(item2, index2) in numList"
|
|
|
+ :key="index2"
|
|
|
+ :style="{
|
|
|
+ lineHeight: `${height}` + 'px',
|
|
|
+ fontSize: width + 'px'
|
|
|
+ }"
|
|
|
+ >{{ item2 }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </li>
|
|
|
+ <span
|
|
|
+ v-if="index != list.length - 1"
|
|
|
+ class="font-bold color-[#fff]"
|
|
|
+ :style="{
|
|
|
+ fontSize: width + 'px'
|
|
|
+ }"
|
|
|
+ >,</span
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.number {
|
|
|
+ margin-bottom: 10px;
|
|
|
+ text-align: center;
|
|
|
+ ul {
|
|
|
+ display: inline-block;
|
|
|
+ text-align: center;
|
|
|
+ list-style: none;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ li {
|
|
|
+ float: left;
|
|
|
+ margin: 0 3px;
|
|
|
+ border-radius: 5px;
|
|
|
+ background: -webkit-linear-gradient(
|
|
|
+ top,
|
|
|
+ v-bind(bgColor) 0%,
|
|
|
+ v-bind(bgColor) 35%,
|
|
|
+ v-bind(centerColor) 55%,
|
|
|
+ v-bind(bgColor) 55%,
|
|
|
+ v-bind(bgColor) 100%
|
|
|
+ );
|
|
|
+ .dataBoc {
|
|
|
+ position: relative;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+ .tt {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ span {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ float: left;
|
|
|
+ color: v-bind(textColor);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|