Browse Source

新增数字翻牌组件

tongshangming 5 months ago
parent
commit
7017af29fd
4 changed files with 230 additions and 3 deletions
  1. 1 0
      src/components.d.ts
  2. 223 0
      src/components/DigitalFlipper.vue
  3. 3 2
      src/components/FsNavbar.vue
  4. 3 1
      src/views/Home.vue

+ 1 - 0
src/components.d.ts

@@ -7,6 +7,7 @@ export {}
 
 declare module 'vue' {
   export interface GlobalComponents {
+    DigitalFlipper: typeof import('./components/DigitalFlipper.vue')['default']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     FsNavbar: typeof import('./components/FsNavbar.vue')['default']
     FsTimer: typeof import('./components/FsTimer.vue')['default']

+ 223 - 0
src/components/DigitalFlipper.vue

@@ -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>

+ 3 - 2
src/components/FsNavbar.vue

@@ -19,7 +19,7 @@ const props = withDefaults(defineProps<Props>(), {
   width: '176px',
   height: '48px',
   activeSrc: navbarActiveBg,
-  gap: '-16px',
+  gap: '16px',
 })
 
 const bgImg = `url(${props.src})`
@@ -36,7 +36,7 @@ const handleClick = (route: string) => {
   <div class="navbar">
     <div
       class="navbar-item"
-      :class="{ active: route.path === item.route }"
+      :class="{ active: route.name === item.route }"
       :style="style"
       v-for="item in nav"
       :key="item.name"
@@ -70,6 +70,7 @@ const handleClick = (route: string) => {
   }
 }
 .active {
+  font-size: 20px;
   background: v-bind(activeBgImg);
 }
 </style>

+ 3 - 1
src/views/Home.vue

@@ -17,7 +17,9 @@ const nav = [
 
     <div class="flex-grow flex w-full p-15px">
       <div class="flex flex-col basis-1/4">
-        <dv-border-box-13> </dv-border-box-13>
+        <dv-border-box-13 class="p-25px">
+          <digital-flipper></digital-flipper>
+        </dv-border-box-13>
         <dv-border-box-13> </dv-border-box-13>
         <dv-border-box-13> </dv-border-box-13>
       </div>