From e4bdfcb0571b51b4d1d55f99df1d1f8ed21c35e3 Mon Sep 17 00:00:00 2001
From: 刘嘉威 <daidaibg@163.com>
Date: 星期一, 17 十月 2022 11:29:36 +0800
Subject: [PATCH] feat: 增加数字滚动组件 展示时间显示

---
 src/components/count-up/count-up.vue         |  146 ++++++++++++++++++++++++++++++++++++
 src/views/HomeView.vue                       |    2 
 package-lock.json                            |   10 ++
 src/components/count-up/index.ts             |    3 
 src/components/scale-screen/scale-screen.vue |    2 
 package.json                                 |    2 
 src/views/header.vue                         |   23 ++++-
 src/views/index.d.ts                         |   27 ++++++
 src/assets/css/main.scss                     |    4 
 9 files changed, 209 insertions(+), 10 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 01ce7d9..c03dd20 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -520,6 +520,11 @@
       "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
       "dev": true
     },
+    "countup.js": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.3.2.tgz",
+      "integrity": "sha512-dQ7F/CmKGjaO6cDfhtEXwsKVlXIpJ89dFs8PvkaZH9jBVJ2Z8GU4iwG/qP7MgY8qwr+1skbwR6qecWWQLUzB8Q=="
+    },
     "cross-spawn": {
       "version": "6.0.5",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
@@ -544,6 +549,11 @@
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz",
       "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w=="
     },
+    "dayjs": {
+      "version": "1.11.5",
+      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.5.tgz",
+      "integrity": "sha512-CAdX5Q3YW3Gclyo5Vpqkgpj8fSdLQcRuzfX6mC6Phy0nfJ0eGYOeS7m4mt2plDWLAtA4TqTakvbboHvUxfe4iA=="
+    },
     "de-indent": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
diff --git a/package.json b/package.json
index 2091954..f33d400 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,8 @@
   },
   "dependencies": {
     "axios": "^1.1.2",
+    "countup.js": "^2.3.2",
+    "dayjs": "^1.11.5",
     "echarts": "^5.4.0",
     "mockjs": "^1.1.0",
     "pinia": "^2.0.21",
diff --git a/src/assets/css/main.scss b/src/assets/css/main.scss
index 20f90dd..2e0cbef 100644
--- a/src/assets/css/main.scss
+++ b/src/assets/css/main.scss
@@ -3,5 +3,7 @@
     width: 100%;
 }
 #app{
-
+    .content_wrap{
+        color: #d3d6dd;
+    }
 }
\ No newline at end of file
diff --git a/src/components/count-up/count-up.vue b/src/components/count-up/count-up.vue
new file mode 100644
index 0000000..2f07b0e
--- /dev/null
+++ b/src/components/count-up/count-up.vue
@@ -0,0 +1,146 @@
+<script lang="ts">
+export type { CountUp as ICountUp, CountUpOptions } from 'countup.js'
+export default {
+  name: 'CountUp'
+}
+</script>
+<script setup lang="ts">
+import { onMounted, onUnmounted, ref, watch } from 'vue'
+import { CountUp } from 'countup.js'
+import type { CountUpOptions } from 'countup.js'
+
+const props = withDefaults(
+  defineProps<{
+    // 缁撴潫鏁板��
+    endVal: number | string
+    // 寮�濮嬫暟鍊�
+    startVal?: number | string
+    // 鍔ㄧ敾鏃堕暱锛屽崟浣� s
+    duration?: number | string
+    // 鏄惁鑷姩璁℃暟
+    autoplay?: boolean
+    // 寰幆娆℃暟锛屾湁闄愭鏁� / 鏃犻檺寰幆
+    loop?: boolean | number | string
+    // 寤舵椂锛屽崟浣� s
+    delay?: number
+    // countup 閰嶇疆椤�
+    options?: CountUpOptions
+  }>(),
+  {
+    startVal: 0,
+    duration: 2.5,
+    autoplay: true,
+    loop: false,
+    delay: 0,
+    options: undefined
+  }
+)
+const emits = defineEmits<{
+  // countup init complete
+  (event: 'init', countup: CountUp): void
+  // count complete
+  (event: 'finished'): void
+}>()
+
+let elRef = ref<HTMLElement>()
+let countUp = ref<CountUp>()
+
+const initCountUp = () => {
+  if (!elRef.value) return
+  const startVal = Number(props.startVal)
+  const endVal = Number(props.endVal)
+  const duration = Number(props.duration)
+  countUp.value = new CountUp(elRef.value, endVal, {
+    startVal,
+    duration,
+    ...props.options
+  })
+  if (countUp.value.error) {
+    console.error(countUp.value.error)
+    return
+  }
+  emits('init', countUp.value)
+}
+
+const startAnim = (cb?: () => void) => {
+  countUp.value?.start(cb)
+}
+
+// endVal change & autoplay: true, restart animate
+watch(
+  () => props.endVal,
+  (value) => {
+    if (props.autoplay) {
+      countUp.value?.update(value)
+    }
+  }
+)
+
+// loop animation
+const finished = ref(false)
+let loopCount = 0
+const loopAnim = () => {
+  loopCount++
+  startAnim(() => {
+    const isTruely = typeof props.loop === 'boolean' && props.loop
+    if (isTruely || props.loop > loopCount) {
+      delay(() => {
+        countUp.value?.reset()
+        loopAnim()
+      }, props.delay)
+    } else {
+      finished.value = true
+    }
+  })
+}
+watch(finished, (flag) => {
+  if (flag) {
+    emits('finished')
+  }
+})
+
+onMounted(() => {
+  initCountUp()
+  if (props.autoplay) {
+    loopAnim()
+  }
+})
+onUnmounted(() => {
+  cancelAnimationFrame(dalayRafId)
+  countUp.value?.reset()
+})
+
+let dalayRafId: number
+// delay to execute callback function
+const delay = (cb: () => unknown, seconds = 1) => {
+  let startTime: number
+  function count(timestamp: number) {
+    if (!startTime) startTime = timestamp
+    const diff = timestamp - startTime
+    if (diff < seconds * 1000) {
+      dalayRafId = requestAnimationFrame(count)
+    } else {
+      cb()
+    }
+  }
+  dalayRafId = requestAnimationFrame(count)
+}
+
+const restart = () => {
+  initCountUp()
+  startAnim()
+}
+
+defineExpose({
+  init: initCountUp,
+  restart
+})
+</script>
+
+<template>
+  <div class="countup-wrap">
+    <slot name="prefix"></slot>
+    <span ref="elRef"> </span>
+    <slot name="suffix"></slot>
+  </div>
+</template>
diff --git a/src/components/count-up/index.ts b/src/components/count-up/index.ts
new file mode 100644
index 0000000..567dc07
--- /dev/null
+++ b/src/components/count-up/index.ts
@@ -0,0 +1,3 @@
+import CountUp from "./count-up.vue"
+export default CountUp
+
diff --git a/src/components/scale-screen/scale-screen.vue b/src/components/scale-screen/scale-screen.vue
index 4420bab..9c4395d 100644
--- a/src/components/scale-screen/scale-screen.vue
+++ b/src/components/scale-screen/scale-screen.vue
@@ -19,7 +19,7 @@
  * @returns {() => void}
  */
 function debounce(fn: Function, delay: number): () => void {
-  // let timer: NodeJS.Timeout;
+  // let timer: NodeJS.Timer;
   let timer: any;
   return function (...args: any[]): void {
     if (timer) clearTimeout(timer);
diff --git a/src/views/HomeView.vue b/src/views/HomeView.vue
index 1372464..1de65e4 100644
--- a/src/views/HomeView.vue
+++ b/src/views/HomeView.vue
@@ -11,7 +11,7 @@
     height="1080"
     :delay="500"
     :fullScreen="false"
-    :boxStyle="{ background: '#000' }"
+    :boxStyle="{ background: '#03050C' }"
     :wrapperStyle="wrapperStyle"
   >
     <div class="content_wrap">
diff --git a/src/views/header.vue b/src/views/header.vue
index 8ffc87f..aba80ff 100644
--- a/src/views/header.vue
+++ b/src/views/header.vue
@@ -1,13 +1,22 @@
 <script setup lang="ts">
 import { reactive } from "vue";
-
-const dateData = reactive({
-  dateDay: null,
-  dateYear: null,
-  dateWeek: null,
-  weekday: ["鍛ㄦ棩", "鍛ㄤ竴", "鍛ㄤ簩", "鍛ㄤ笁", "鍛ㄥ洓", "鍛ㄤ簲", "鍛ㄥ叚"],
+import dayjs from 'dayjs';
+import type {DateDataType} from "./index.d"
+const dateData = reactive<DateDataType>({
+  dateDay: "",
+  dateYear: "",
+  dateWeek: "",
+  timing:null
 });
-
+  
+const weekday= ["鍛ㄦ棩", "鍛ㄤ竴", "鍛ㄤ簩", "鍛ㄤ笁", "鍛ㄥ洓", "鍛ㄤ簲", "鍛ㄥ叚"]
+const timeFn = () => {
+  dateData.timing = setInterval(() => {
+    dateData.dateDay = dayjs().format("YYYY-MM-DD hh : mm : ss");
+    dateData.dateWeek = weekday[dayjs().day()];
+  }, 1000);
+};
+timeFn()
 const showSetting = () => {};
 </script>
 
diff --git a/src/views/index.d.ts b/src/views/index.d.ts
new file mode 100644
index 0000000..594c11e
--- /dev/null
+++ b/src/views/index.d.ts
@@ -0,0 +1,27 @@
+export interface DateDataType {
+    dateDay: string,
+    dateYear: string,
+    dateWeek: string,
+    timing: NodeJS.Timer
+}   
+
+interface CountUpOptions {
+    startVal?: number; // number to start at (0)
+    decimalPlaces?: number; // number of decimal places (0)
+    duration?: number; // animation duration in seconds (2)
+    useGrouping?: boolean; // example: 1,000 vs 1000 (true)
+    useEasing?: boolean; // ease animation (true)
+    smartEasingThreshold?: number; // smooth easing for large numbers above this if useEasing (999)
+    smartEasingAmount?: number; // amount to be eased for numbers above threshold (333)
+    separator?: string; // grouping separator (',')
+    decimal?: string; // decimal ('.')
+    // easingFn: easing function for animation (easeOutExpo)
+    easingFn?: (t: number, b: number, c: number, d: number) => number;
+    formattingFn?: (n: number) => string; // this function formats result
+    prefix?: string; // text prepended to result
+    suffix?: string; // text appended to result
+    numerals?: string[]; // numeral glyph substitution
+    enableScrollSpy?: boolean; // start animation when target is in view
+    scrollSpyDelay?: number; // delay (ms) after target comes into view
+    scrollSpyOnce?: boolean; // run only once
+  }
\ No newline at end of file

--
Gitblit v1.8.0