Ver Fonte

perf: 优化翻牌组件

tnt group há 3 anos atrás
pai
commit
a56ddc9415
1 ficheiros alterados com 61 adições e 53 exclusões
  1. 61 53
      src/components/Flipper/index.vue

+ 61 - 53
src/components/Flipper/index.vue

@@ -1,24 +1,28 @@
 <template>
   <div class="M-Flipper" :class="[flipType, { go: isFlipping }]">
-    <div class="digital front" :data-front="frontTextFromData"></div>
-    <div class="digital back" :data-back="backTextFromData"></div>
+    <div class="digital front" :data-front="frontTextFromData || 0"></div>
+    <div class="digital back" :data-back="backTextFromData || 0"></div>
   </div>
 </template>
 
 <script lang="ts" setup>
-import { ref } from 'vue'
+import { ref, PropType, watch } from 'vue'
 type FlipType = 'up' | 'down'
 
-const name = 'Flipper'
-
 const props = defineProps({
+  flipType: {
+    type: Object as PropType<FlipType>,
+    default: () => {
+      return 'down'
+    }
+  },
   frontText: {
     type: [Number, String],
     default: 0
   },
   backText: {
     type: [Number, String],
-    default: 1
+    default: 0
   },
   duration: {
     type: Number,
@@ -47,97 +51,101 @@ const props = defineProps({
 })
 
 const isFlipping = ref(false)
-const flipType = ref<FlipType>('down')
 const frontTextFromData = ref(props.frontText)
 const backTextFromData = ref(props.backText)
 
-const _flip = (type: FlipType, front: string | number, back: string | number) => {
+// 翻牌
+const flip = (front: string | number, back: string | number) => {
   // 如果处于翻转中,则不执行
   if (isFlipping.value) return
-  frontTextFromData.value = front
+  // 设置翻盘前后数据
   backTextFromData.value = back
-  // 根据传递过来的type设置翻转方向
-  flipType.value = type
+  frontTextFromData.value = front
+
   // 设置翻转状态为true
   isFlipping.value = true
+
+  // 翻牌结束的行为
   setTimeout(() => {
-    // 设置翻转状态为false
-    isFlipping.value = false
+    isFlipping.value = false // 设置翻转状态为false
     frontTextFromData.value = back
   }, props.duration)
 }
-// 下翻牌
-const flipDown = (front: string | number, back: string | number) => _flip('down', front, back)
-// 上翻牌
-const flipUp = (front: string | number, back: string | number) => _flip('up', front, back)
-// 设置前牌文字
-const setFront = (text: string | number) => {
-  frontTextFromData.value = text
-}
-// 设置后牌文字
-const setBack = (text: string | number) => {
-  backTextFromData.value = text
-}
+
+watch(
+  () => props.backText,
+  (newVal, oldVal) => {
+    console.log('watch:props.backText', newVal)
+    flip(newVal, oldVal as string | number)
+  },
+  {
+    immediate: true
+  }
+)
 
 defineExpose({
-  name,
-  flipDown,
-  flipUp
+  flip
 })
 </script>
 
 <style lang="scss" scoped>
+// #region 动画效果
 @keyframes frontFlipDown {
   0% {
-    transform: perspective(160px) rotateX(0deg);
+    transform: perspective(v-bind('`${props.height * 1.6}px`')) rotateX(0deg);
   }
   100% {
-    transform: perspective(160px) rotateX(-180deg);
+    transform: perspective(v-bind('`${props.height * 1.6}px`')) rotateX(-180deg);
   }
 }
 @keyframes backFlipDown {
   0% {
-    transform: perspective(160px) rotateX(180deg);
+    transform: perspective(v-bind('`${props.height * 1.6}px`')) rotateX(180deg);
   }
   100% {
-    transform: perspective(160px) rotateX(0deg);
+    transform: perspective(v-bind('`${props.height * 1.6}px`')) rotateX(0deg);
   }
 }
 @keyframes frontFlipUp {
   0% {
-    transform: perspective(160px) rotateX(0deg);
+    transform: perspective(v-bind('`${props.height * 1.6}px`')) rotateX(0deg);
   }
   100% {
-    transform: perspective(160px) rotateX(180deg);
+    transform: perspective(v-bind('`${props.height * 1.6}px`')) rotateX(180deg);
   }
 }
 @keyframes backFlipUp {
   0% {
-    transform: perspective(160px) rotateX(-180deg);
+    transform: perspective(v-bind('`${props.height * 1.6}px`')) rotateX(-180deg);
   }
   100% {
-    transform: perspective(160px) rotateX(0deg);
+    transform: perspective(v-bind('`${props.height * 1.6}px`')) rotateX(0deg);
   }
 }
+// #endregion
 
 $frontColor: v-bind('props.frontColor');
 $backColor: v-bind('props.backColor');
-$radius: v-bind('props.radius');
+$radius: v-bind('`${props.radius}px`');
+$width: v-bind('`${props.width}px`');
+$height: v-bind('`${props.height}px`');
+$shadowColor: #000000;
+$lineColor: #ffffff;
 
 .M-Flipper {
   display: inline-block;
   position: relative;
-  width: v-bind('`${width}px`');
-  height: v-bind('`${height}px`');
-  line-height: v-bind('`${height}px`');
+  width: $width;
+  height: $height;
+  line-height: $height;
   border: solid 1px $backColor;
-  border-radius: v-bind('`${radius}px`');
+  border-radius: $radius;
   background: $frontColor;
-  font-size: v-bind('`${width * 1.1}px`');
-  color: v-bind('props.frontColor');
-  box-shadow: 0 0 6px rgba(0, 0, 0, 0.5);
+  font-size: v-bind('`${props.width * 1.1}px`');
+  color: $frontColor;
+  box-shadow: 0 0 6px rgba($color: $shadowColor, $alpha: 0.5); // 阴影部分
   text-align: center;
-  font-family: 'Helvetica Neue';
+  // font-family: 'Helvetica Neue';
 
   .digital:before,
   .digital:after {
@@ -145,7 +153,7 @@ $radius: v-bind('props.radius');
     position: absolute;
     left: 0;
     right: 0;
-    background: v-bind('props.backColor');
+    background: $backColor;
     overflow: hidden;
     box-sizing: border-box;
   }
@@ -160,13 +168,13 @@ $radius: v-bind('props.radius');
   .digital:before {
     top: 0;
     bottom: 50%;
-    border-radius: v-bind('`${radius}px`') v-bind('`${radius}px`') 0 0;
-    border-bottom: solid 1px #666;
+    border-radius: $radius $radius 0 0;
+    border-bottom: solid 1px rgba($color: $lineColor, $alpha: 0.5); // 中间线颜色
   }
   .digital:after {
     top: 50%;
     bottom: 0;
-    border-radius: 0 0 v-bind('`${radius}px`') v-bind('`${radius}px`');
+    border-radius: 0 0 $radius $radius;
     line-height: 0;
   }
   /*向下翻*/
@@ -176,7 +184,7 @@ $radius: v-bind('props.radius');
   &.down .back:after {
     z-index: 2;
     transform-origin: 50% 0%;
-    transform: perspective(v-bind('`${height * 1.6}px`')) rotateX(180deg);
+    transform: perspective(v-bind('`${props.height * 1.6}px`')) rotateX(180deg);
   }
   &.down .front:after,
   &.down .back:before {
@@ -185,7 +193,7 @@ $radius: v-bind('props.radius');
   &.down.go .front:before {
     transform-origin: 50% 100%;
     animation: frontFlipDown v-bind('`${props.duration / 1000}s`') ease-in-out both;
-    box-shadow: 0 -2px 6px rgba(255, 255, 255, 0.3);
+    box-shadow: 0 -2px 6px rgba($color: $lineColor, $alpha: 0.3);
     backface-visibility: hidden;
   }
   &.down.go .back:after {
@@ -198,7 +206,7 @@ $radius: v-bind('props.radius');
   &.up .back:before {
     z-index: 2;
     transform-origin: 50% 100%;
-    transform: perspective(v-bind('`${height * 1.6}px`')) rotateX(-180deg);
+    transform: perspective(v-bind('`${props.height * 1.6}px`')) rotateX(-180deg);
   }
   &.up .front:before,
   &.up .back:after {
@@ -207,7 +215,7 @@ $radius: v-bind('props.radius');
   &.up.go .front:after {
     transform-origin: 50% 0;
     animation: frontFlipUp v-bind('`${props.duration / 1000}s`') ease-in-out both;
-    box-shadow: 0 2px 6px rgba(255, 255, 255, 0.3);
+    box-shadow: 0 2px 6px rgba($color: $lineColor, $alpha: 0.3);
     backface-visibility: hidden;
   }
   &.up.go .back:before {