index.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. <template>
  2. <div class="M-Flipper" :class="[flipType, { go: isFlipping }]">
  3. <div class="digital front" :data-front="frontTextFromData"></div>
  4. <div class="digital back" :data-back="backTextFromData"></div>
  5. </div>
  6. </template>
  7. <script lang="ts">
  8. export default {
  9. name: 'Flipper'
  10. }
  11. </script>
  12. <script lang="ts" setup>
  13. import { ref, PropType, watch } from 'vue'
  14. import { FlipType } from '.'
  15. const props = defineProps({
  16. flipType: {
  17. type: String as PropType<FlipType>,
  18. default: () => {
  19. return 'down'
  20. }
  21. },
  22. count: {
  23. type: [Number, String],
  24. default: 0
  25. },
  26. duration: {
  27. type: Number,
  28. default: 600
  29. },
  30. width: {
  31. type: Number,
  32. default: 60
  33. },
  34. height: {
  35. type: Number,
  36. default: 100
  37. },
  38. radius: {
  39. type: Number,
  40. default: 10
  41. },
  42. frontColor: {
  43. type: String,
  44. default: '#ffffff'
  45. },
  46. backColor: {
  47. type: String,
  48. default: '#000000'
  49. }
  50. })
  51. const isFlipping = ref(false)
  52. const frontTextFromData = ref(props.count || 0)
  53. const backTextFromData = ref(props.count || 0)
  54. // 翻牌
  55. const flip = (front: string | number, back: string | number) => {
  56. // 如果处于翻转中,则不执行
  57. if (isFlipping.value) return
  58. // 设置翻盘前后数据
  59. backTextFromData.value = back
  60. frontTextFromData.value = front
  61. // 设置翻转状态为true
  62. isFlipping.value = true
  63. // 翻牌结束的行为
  64. setTimeout(() => {
  65. isFlipping.value = false // 设置翻转状态为false
  66. frontTextFromData.value = back
  67. }, props.duration)
  68. }
  69. watch(
  70. () => props.count,
  71. (newVal, oldVal) => {
  72. flip(oldVal as string | number, newVal as string | number)
  73. },
  74. {
  75. immediate: true
  76. }
  77. )
  78. </script>
  79. <style lang="scss" scoped>
  80. $frontColor: v-bind('props.frontColor');
  81. $backColor: v-bind('props.backColor');
  82. $radius: v-bind('`${props.radius}px`');
  83. $width: v-bind('`${props.width}px`');
  84. $height: v-bind('`${props.height}px`');
  85. $perspective: v-bind('`${props.height * 2}px`');
  86. $speed: v-bind('`${props.duration / 1000}s`');
  87. $shadowColor: #000000;
  88. $lineColor: #4a9ef8;
  89. // #region 动画效果
  90. @keyframes frontFlipDown {
  91. 0% {
  92. transform: perspective($perspective) rotateX(0deg);
  93. }
  94. 100% {
  95. transform: perspective($perspective) rotateX(-180deg);
  96. }
  97. }
  98. @keyframes backFlipDown {
  99. 0% {
  100. transform: perspective($perspective) rotateX(180deg);
  101. }
  102. 100% {
  103. transform: perspective($perspective) rotateX(0deg);
  104. }
  105. }
  106. @keyframes frontFlipUp {
  107. 0% {
  108. transform: perspective($perspective) rotateX(0deg);
  109. }
  110. 100% {
  111. transform: perspective($perspective) rotateX(180deg);
  112. }
  113. }
  114. @keyframes backFlipUp {
  115. 0% {
  116. transform: perspective($perspective) rotateX(-180deg);
  117. }
  118. 100% {
  119. transform: perspective($perspective) rotateX(0deg);
  120. }
  121. }
  122. // #endregion
  123. .M-Flipper {
  124. display: inline-block;
  125. position: relative;
  126. width: $width;
  127. height: $height;
  128. line-height: $height;
  129. border: solid 1px $backColor;
  130. border-radius: $radius;
  131. background: $frontColor;
  132. font-size: $width;
  133. color: $frontColor;
  134. box-shadow: 0 0 6px rgba($color: $shadowColor, $alpha: 0.5); // 阴影部分
  135. text-align: center;
  136. // font-family: 'Helvetica Neue';
  137. .digital:before,
  138. .digital:after {
  139. content: '';
  140. position: absolute;
  141. left: 0;
  142. right: 0;
  143. background: $backColor;
  144. overflow: hidden;
  145. box-sizing: border-box;
  146. }
  147. .digital.front:before,
  148. .digital.front:after {
  149. content: attr(data-front) !important;
  150. }
  151. .digital.back:before,
  152. .digital.back:after {
  153. content: attr(data-back) !important;
  154. }
  155. .digital:before {
  156. top: 0;
  157. bottom: 50%;
  158. border-radius: $radius $radius 0 0;
  159. border-bottom: solid 1px rgba($color: $lineColor, $alpha: 0.3); // 中间线颜色
  160. }
  161. .digital:after {
  162. top: 50%;
  163. bottom: 0;
  164. border-radius: 0 0 $radius $radius;
  165. line-height: 0;
  166. }
  167. /*向下翻*/
  168. &.down .front:before {
  169. z-index: 3;
  170. }
  171. &.down .back:after {
  172. z-index: 2;
  173. transform-origin: 50% 0%;
  174. transform: perspective($perspective) rotateX(180deg);
  175. }
  176. &.down .front:after,
  177. &.down .back:before {
  178. z-index: 1;
  179. }
  180. &.down.go .front:before {
  181. transform-origin: 50% 100%;
  182. animation: frontFlipDown $speed ease-in-out both;
  183. box-shadow: 0 -2px 6px rgba($color: $lineColor, $alpha: 0.3);
  184. backface-visibility: hidden;
  185. }
  186. &.down.go .back:after {
  187. animation: backFlipDown $speed ease-in-out both;
  188. }
  189. /*向上翻*/
  190. &.up .front:after {
  191. z-index: 3;
  192. }
  193. &.up .back:before {
  194. z-index: 2;
  195. transform-origin: 50% 100%;
  196. transform: perspective($perspective) rotateX(-180deg);
  197. }
  198. &.up .front:before,
  199. &.up .back:after {
  200. z-index: 1;
  201. }
  202. &.up.go .front:after {
  203. transform-origin: 50% 0;
  204. animation: frontFlipUp $speed ease-in-out both;
  205. box-shadow: 0 2px 6px rgba($color: $lineColor, $alpha: 0.3);
  206. backface-visibility: hidden;
  207. }
  208. &.up.go .back:before {
  209. animation: backFlipUp $speed ease-in-out both;
  210. }
  211. }
  212. </style>