Forráskód Böngészése

feat: add flop plug-in unit

xiaoxian521 4 éve
szülő
commit
637808f88b

+ 1 - 0
package.json

@@ -10,6 +10,7 @@
     "@amap/amap-jsapi-loader": "^1.0.1",
     "await-to-js": "^2.1.1",
     "axios": "^0.21.1",
+    "dayjs": "^1.10.4",
     "dotenv": "^8.2.0",
     "element-plus": "^1.0.2-beta.36",
     "font-awesome": "^4.7.0",

+ 280 - 0
src/components/flop/flipper.vue

@@ -0,0 +1,280 @@
+<template>
+  <div class="m-flipper" :class="[flipType, {'go': isFlipping}]">
+    <div class="digital front" :class="textClass(frontTextFromData)"></div>
+    <div class="digital back" :class="textClass(backTextFromData)"></div>
+  </div>
+</template>
+
+<script lang='ts'>
+import { defineComponent, ref } from "vue";
+export default defineComponent({
+  props: {
+    // front paper text
+    // 前牌文字
+    frontText: {
+      type: [Number, String],
+      default: 0,
+    },
+    // back paper text
+    // 后牌文字
+    backText: {
+      type: [Number, String],
+      default: 1,
+    },
+    // flipping duration, please be consistent with the CSS animation-duration value.
+    // 翻牌动画时间,与CSS中设置的animation-duration保持一致
+    duration: {
+      type: Number,
+      default: 600,
+    },
+  },
+  setup(props) {
+    const { frontText, backText, duration } = props;
+    let isFlipping = ref(false);
+    let flipType = ref("down");
+    let frontTextFromData = ref(frontText);
+    let backTextFromData = ref(backText);
+
+    const textClass = (number: string) => {
+      return "number" + number;
+    };
+
+    const flip = (type: string, front: number, back: number) => {
+      // 如果处于翻转中,则不执行
+      if (isFlipping.value) return false;
+      frontTextFromData.value = front;
+      backTextFromData.value = back;
+      // 根据传递过来的type设置翻转方向
+      flipType.value = type;
+      // 设置翻转状态为true
+      isFlipping.value = true;
+
+      setTimeout(() => {
+        // 设置翻转状态为false
+        isFlipping.value = false;
+        frontTextFromData.value = back;
+      }, duration);
+    };
+
+    // 下翻牌
+    const flipDown = (front: any, back: any): void => {
+      flip("down", front, back);
+    };
+
+    // 上翻牌
+    const flipUp = (front: any, back: any): void => {
+      flip("up", front, back);
+    };
+
+    // 设置前牌文字
+    const setFront = (text: number): void => {
+      frontTextFromData.value = text;
+    };
+
+    // 设置后牌文字
+    const setBack = (text: number): void => {
+      backTextFromData.value = text;
+    };
+
+    return {
+      isFlipping,
+      flipType,
+      frontTextFromData,
+      backTextFromData,
+      textClass,
+      flip,
+      flipDown,
+      flipUp,
+      setFront,
+      setBack,
+    };
+  },
+});
+</script>
+
+<style>
+.m-flipper {
+  display: inline-block;
+  position: relative;
+  width: 60px;
+  height: 100px;
+  line-height: 100px;
+  border: solid 1px #000;
+  border-radius: 10px;
+  background: #fff;
+  font-size: 66px;
+  color: #fff;
+  box-shadow: 0 0 6px rgba(0, 0, 0, 0.5);
+  text-align: center;
+  font-family: "Helvetica Neue";
+}
+
+.m-flipper .digital:before,
+.m-flipper .digital:after {
+  content: "";
+  position: absolute;
+  left: 0;
+  right: 0;
+  background: #000;
+  overflow: hidden;
+  box-sizing: border-box;
+}
+
+.m-flipper .digital:before {
+  top: 0;
+  bottom: 50%;
+  border-radius: 10px 10px 0 0;
+  border-bottom: solid 1px #666;
+}
+
+.m-flipper .digital:after {
+  top: 50%;
+  bottom: 0;
+  border-radius: 0 0 10px 10px;
+  line-height: 0;
+}
+
+/*向下翻*/
+.m-flipper.down .front:before {
+  z-index: 3;
+}
+
+.m-flipper.down .back:after {
+  z-index: 2;
+  transform-origin: 50% 0%;
+  transform: perspective(160px) rotateX(180deg);
+}
+
+.m-flipper.down .front:after,
+.m-flipper.down .back:before {
+  z-index: 1;
+}
+
+.m-flipper.down.go .front:before {
+  transform-origin: 50% 100%;
+  animation: frontFlipDown 0.6s ease-in-out both;
+  box-shadow: 0 -2px 6px rgba(255, 255, 255, 0.3);
+  backface-visibility: hidden;
+}
+
+.m-flipper.down.go .back:after {
+  animation: backFlipDown 0.6s ease-in-out both;
+}
+
+/*向上翻*/
+.m-flipper.up .front:after {
+  z-index: 3;
+}
+
+.m-flipper.up .back:before {
+  z-index: 2;
+  transform-origin: 50% 100%;
+  transform: perspective(160px) rotateX(-180deg);
+}
+
+.m-flipper.up .front:before,
+.m-flipper.up .back:after {
+  z-index: 1;
+}
+
+.m-flipper.up.go .front:after {
+  transform-origin: 50% 0;
+  animation: frontFlipUp 0.6s ease-in-out both;
+  box-shadow: 0 2px 6px rgba(255, 255, 255, 0.3);
+  backface-visibility: hidden;
+}
+
+.m-flipper.up.go .back:before {
+  animation: backFlipUp 0.6s ease-in-out both;
+}
+
+@keyframes frontFlipDown {
+  0% {
+    transform: perspective(160px) rotateX(0deg);
+  }
+
+  100% {
+    transform: perspective(160px) rotateX(-180deg);
+  }
+}
+
+@keyframes backFlipDown {
+  0% {
+    transform: perspective(160px) rotateX(180deg);
+  }
+
+  100% {
+    transform: perspective(160px) rotateX(0deg);
+  }
+}
+
+@keyframes frontFlipUp {
+  0% {
+    transform: perspective(160px) rotateX(0deg);
+  }
+
+  100% {
+    transform: perspective(160px) rotateX(180deg);
+  }
+}
+
+@keyframes backFlipUp {
+  0% {
+    transform: perspective(160px) rotateX(-180deg);
+  }
+
+  100% {
+    transform: perspective(160px) rotateX(0deg);
+  }
+}
+
+.m-flipper .number0:before,
+.m-flipper .number0:after {
+  content: "0";
+}
+
+.m-flipper .number1:before,
+.m-flipper .number1:after {
+  content: "1";
+}
+
+.m-flipper .number2:before,
+.m-flipper .number2:after {
+  content: "2";
+}
+
+.m-flipper .number3:before,
+.m-flipper .number3:after {
+  content: "3";
+}
+
+.m-flipper .number4:before,
+.m-flipper .number4:after {
+  content: "4";
+}
+
+.m-flipper .number5:before,
+.m-flipper .number5:after {
+  content: "5";
+}
+
+.m-flipper .number6:before,
+.m-flipper .number6:after {
+  content: "6";
+}
+
+.m-flipper .number7:before,
+.m-flipper .number7:after {
+  content: "7";
+}
+
+.m-flipper .number8:before,
+.m-flipper .number8:after {
+  content: "8";
+}
+
+.m-flipper .number9:before,
+.m-flipper .number9:after {
+  content: "9";
+}
+</style>

+ 135 - 0
src/components/flop/index.vue

@@ -0,0 +1,135 @@
+<template>
+  <div class="flip-clock">
+    <flippers ref="flipperHour1" />
+    <flippers ref="flipperHour2" />
+    <em>:</em>
+    <flippers ref="flipperMinute1" />
+    <flippers ref="flipperMinute2" />
+    <em>:</em>
+    <flippers ref="flipperSecond1" />
+    <flippers ref="flipperSecond2" />
+  </div>
+</template>
+
+<script lang='ts'>
+import { ref, onBeforeMount, getCurrentInstance, nextTick } from "vue";
+import flippers from "./flipper.vue";
+export default {
+  components: {
+    flippers,
+  },
+  setup() {
+    let vm: any;
+    let timer = ref(null);
+    let flipObjs = ref([]);
+
+    // 初始化数字
+    const init = () => {
+      let now = new Date();
+      let nowTimeStr = formatDate(new Date(now.getTime()), "hhiiss");
+      for (let i = 0; i < flipObjs.value.length; i++) {
+        flipObjs.value[i].setFront(nowTimeStr[i]);
+      }
+    };
+
+    // 开始计时
+    const run = () => {
+      timer.value = setInterval(() => {
+        // 获取当前时间
+        let now = new Date();
+        let nowTimeStr = formatDate(new Date(now.getTime() - 1000), "hhiiss");
+        let nextTimeStr = formatDate(now, "hhiiss");
+        for (let i = 0; i < flipObjs.value.length; i++) {
+          if (nowTimeStr[i] === nextTimeStr[i]) {
+            continue;
+          }
+          flipObjs.value[i].flipDown(nowTimeStr[i], nextTimeStr[i]);
+        }
+      }, 1000);
+    };
+
+    // 正则格式化日期
+    const formatDate = (date: Date, dateFormat: string) => {
+      /* 单独格式化年份,根据y的字符数量输出年份
+     * 例如:yyyy => 2019
+            yy => 19
+            y => 9
+     */
+      if (/(y+)/.test(dateFormat)) {
+        dateFormat = dateFormat.replace(
+          RegExp.$1,
+          (date.getFullYear() + "").substr(4 - RegExp.$1.length)
+        );
+      }
+      // 格式化月、日、时、分、秒
+      let o = {
+        "m+": date.getMonth() + 1,
+        "d+": date.getDate(),
+        "h+": date.getHours(),
+        "i+": date.getMinutes(),
+        "s+": date.getSeconds(),
+      };
+      for (let k in o) {
+        if (new RegExp(`(${k})`).test(dateFormat)) {
+          // 取出对应的值
+          let str = o[k] + "";
+          /* 根据设置的格式,输出对应的字符
+           * 例如: 早上8时,hh => 08,h => 8
+           * 但是,当数字>=10时,无论格式为一位还是多位,不做截取,这是与年份格式化不一致的地方
+           * 例如: 下午15时,hh => 15, h => 15
+           */
+          dateFormat = dateFormat.replace(
+            RegExp.$1,
+            RegExp.$1.length === 1 ? str : padLeftZero(str)
+          );
+        }
+      }
+      return dateFormat;
+    };
+
+    // 日期时间补零
+    const padLeftZero = (str: string | any[]) => {
+      return ("00" + str).substr(str.length);
+    };
+
+    onBeforeMount(() => {
+      vm = getCurrentInstance(); //获取组件实例
+      nextTick(() => {
+        flipObjs.value = [
+          vm.refs.flipperHour1,
+          vm.refs.flipperHour2,
+          vm.refs.flipperMinute1,
+          vm.refs.flipperMinute2,
+          vm.refs.flipperSecond1,
+          vm.refs.flipperSecond2,
+        ];
+
+        init();
+        run();
+      });
+    });
+
+    return {
+      timer,
+      flipObjs,
+      init,
+      run,
+      formatDate,
+      padLeftZero,
+    };
+  },
+};
+</script>
+
+<style>
+.flip-clock .m-flipper {
+  margin: 0 3px;
+}
+.flip-clock em {
+  display: inline-block;
+  line-height: 102px;
+  font-size: 66px;
+  font-style: normal;
+  vertical-align: top;
+}
+</style>

+ 1 - 1
src/layout/components/AppMain.vue

@@ -28,7 +28,7 @@ export default defineComponent({
 
 <style scoped>
 .app-main {
-  /* min-height: calc(100vh - 50px); */
+  min-height: calc(100vh - 70px);
   width: 100%;
   position: relative;
   overflow-x: hidden;

+ 4 - 100
src/views/welcome.vue

@@ -1,112 +1,16 @@
 <template>
   <div class="welcome">
-    <a title="欢迎Star" href="https://github.com/xiaoxian521/CURD-TS" target="_blank">点击打开仓库地址</a>
-    <Renderer
-      ref="renderer"
-      antialias
-      resize
-      :orbit-ctrl="{ enableDamping: true, dampingFactor: 0.05 }"
-    >
-      <Camera :position="{ x: -0, y: -100, z: 30 }" />
-      <Scene background="#ffffff">
-        <PointLight
-          ref="light1"
-          color="#0E09DC"
-          :intensity="0.85"
-          :position="{ x: 0, y: 0, z: 50 }"
-        />
-        <PointLight
-          ref="light2"
-          color="#1CD1E1"
-          :intensity="0.85"
-          :position="{ x: 0, y: 0, z: 50 }"
-        />
-        <PointLight
-          ref="light3"
-          color="#18C02C"
-          :intensity="0.85"
-          :position="{ x: 0, y: 0, z: 50 }"
-        />
-        <PointLight
-          ref="light4"
-          color="#ee3bcf"
-          :intensity="0.85"
-          :position="{ x: 0, y: 0, z: 50 }"
-        />
-
-        <NoisyPlane
-          :width="120"
-          :width-segments="120"
-          :height="100"
-          :height-segments="120"
-          :time-coef="0.0003"
-          :noise-coef="5"
-          :displacement-scale="20"
-          :delta-coef="1 / 120"
-          :position="{ x: 0, y: 0, z: 0 }"
-        >
-          <PhysicalMaterial />
-        </NoisyPlane>
-
-        <RefractionMesh ref="mesh" :position="{ x: 0, y: -20, z: 20 }" auto-update>
-          <TorusGeometry :radius="8" :tube="3" :radial-segments="8" :tubular-segments="6" />
-          <StandardMaterial color="#ffffff" :metalness="1" :roughness="0" flat-shading />
-        </RefractionMesh>
-      </Scene>
-    </Renderer>
+    <!-- <a title="欢迎Star" href="https://github.com/xiaoxian521/CURD-TS" target="_blank">点击打开仓库地址</a> -->
+    <flop />
   </div>
 </template>
 
 <script lang='ts'>
-import {
-  Camera,
-  PhysicalMaterial,
-  PointLight,
-  RefractionMesh,
-  Renderer,
-  Scene,
-  StandardMaterial,
-  TorusGeometry,
-} from "troisjs";
-import NoisyPlane from "troisjs/src/components/noisy/NoisyPlane.js";
-import NoisySphere from "troisjs/src/components/noisy/NoisySphere.js";
-import NoisyText from "troisjs/src/components/noisy/NoisyText.js";
+import flop from "../components/flop/index.vue"
 export default {
   name: "welcome",
   components: {
-    Camera,
-    NoisyPlane,
-    NoisySphere,
-    NoisyText,
-    PhysicalMaterial,
-    PointLight,
-    RefractionMesh,
-    Renderer,
-    Scene,
-    StandardMaterial,
-    TorusGeometry,
-  },
-  mounted() {
-    const renderer = this.$refs.renderer;
-    const light1 = this.$refs.light1.light;
-    const light2 = this.$refs.light2.light;
-    const light3 = this.$refs.light3.light;
-    const light4 = this.$refs.light4.light;
-    const mesh = this.$refs.mesh.mesh;
-    renderer.onBeforeRender(() => {
-      const time = Date.now() * 0.001;
-      const d = 100;
-      light1.position.x = Math.sin(time * 0.1) * d;
-      light1.position.y = Math.cos(time * 0.2) * d;
-      light2.position.x = Math.cos(time * 0.3) * d;
-      light2.position.y = Math.sin(time * 0.4) * d;
-      light3.position.x = Math.sin(time * 0.5) * d;
-      light3.position.y = Math.sin(time * 0.6) * d;
-      light4.position.x = Math.sin(time * 0.7) * d;
-      light4.position.y = Math.cos(time * 0.8) * d;
-      mesh.rotation.x += 0.02;
-      mesh.rotation.y += 0.01;
-    });
+    flop
   },
 };
 </script>