big-wheel.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. <route lang="json5">
  2. {
  3. style: { navigationBarTitleText: '大转盘抽奖' },
  4. }
  5. </route>
  6. <template>
  7. <view>
  8. <view class="container">
  9. <view class="prize-list" :style="styleObj">
  10. <view
  11. class="prize-item"
  12. v-for="(item, index) in prizeList"
  13. :key="item.id"
  14. :style="prizeStyle(index)"
  15. >
  16. <image :src="item.pic" class="gift-img" />
  17. <text class="gift-name">{{ item.name }}</text>
  18. </view>
  19. </view>
  20. <view class="lottery-btn" @click="start"> </view>
  21. </view>
  22. </view>
  23. </template>
  24. <script lang="ts" setup>
  25. import { ref, computed } from 'vue'
  26. // 后台配置的奖品数据
  27. const prizeList = [
  28. {
  29. id: 0,
  30. name: '双肩包',
  31. pic: 'https://cip-shopping-page-0eysug01066a9e-1302818703.tcloudbaseapp.com/fly/lottery-prize/backpack.jpg',
  32. },
  33. {
  34. id: 1,
  35. name: '积木',
  36. pic: 'https://cip-shopping-page-0eysug01066a9e-1302818703.tcloudbaseapp.com/fly/lottery-prize/jimu.jpg',
  37. },
  38. {
  39. id: 2,
  40. name: '红包',
  41. pic: 'https://cip-shopping-page-0eysug01066a9e-1302818703.tcloudbaseapp.com/fly/lottery-prize/red-envelope.jpg',
  42. },
  43. {
  44. id: 3,
  45. name: '茶具',
  46. pic: 'https://cip-shopping-page-0eysug01066a9e-1302818703.tcloudbaseapp.com/fly/lottery-prize/tea-set.jpg',
  47. },
  48. {
  49. id: 4,
  50. name: '可爱脸',
  51. pic: 'https://cip-shopping-page-0eysug01066a9e-1302818703.tcloudbaseapp.com/fly/lottery-prize/tushetou.jpg',
  52. },
  53. {
  54. id: 5,
  55. name: '挖掘机',
  56. pic: 'https://cip-shopping-page-0eysug01066a9e-1302818703.tcloudbaseapp.com/fly/lottery-prize/wajueji.jpg',
  57. },
  58. {
  59. id: 6,
  60. name: '无辜脸',
  61. pic: 'https://cip-shopping-page-0eysug01066a9e-1302818703.tcloudbaseapp.com/fly/lottery-prize/xiaolian.jpg',
  62. },
  63. {
  64. id: 7,
  65. name: '烟灰缸',
  66. pic: 'https://cip-shopping-page-0eysug01066a9e-1302818703.tcloudbaseapp.com/fly/lottery-prize/yanhuigang.jpg',
  67. },
  68. ]
  69. let isRunning = false // 是否正在抽奖
  70. const baseRunAngle = 360 * 5 // 总共转动角度 至少5圈
  71. let prizeId = 0 // 中奖id
  72. // 平均每个奖品角度
  73. const rotateAngle = computed(() => {
  74. const _degree = 360 / prizeList.length
  75. return _degree
  76. })
  77. // 要执行总角度数
  78. const totalRunAngle = computed(() => {
  79. return baseRunAngle + 360 - prizeId * rotateAngle.value - rotateAngle.value / 2
  80. })
  81. // 计算绘制转盘背景
  82. const bgColor = (() => {
  83. const [c1, c2] = ['#5352b3', '#363589']
  84. // repeating-conic-gradient(red 0 15deg, blue 15deg 30deg);
  85. return `background: repeating-conic-gradient(${c1} 0 ${rotateAngle.value}deg,
  86. ${c2} ${rotateAngle.value}deg ${2 * rotateAngle.value}deg);`
  87. })()
  88. const styleObj = ref(bgColor)
  89. // 每个奖品布局
  90. const prizeStyle = computed(() => {
  91. const _degree = rotateAngle.value
  92. return (i) => {
  93. // 外框大小设置为90vw,里面是一半,45vw
  94. return `
  95. width: ${2 * 45 * Math.sin(((_degree / 2) * Math.PI) / 180)}vw;
  96. height: 45vw;
  97. transform: rotate(${_degree * i + _degree / 2}deg);
  98. transform-origin: 50% 100%;
  99. `
  100. }
  101. })
  102. // 获取随机数
  103. const getRandomNum = () => {
  104. const num = Math.floor(Math.random() * prizeList.length)
  105. return num
  106. }
  107. const stopRun = () => {
  108. isRunning = false
  109. styleObj.value = `${bgColor} transform: rotate(${totalRunAngle.value - baseRunAngle}deg);`
  110. }
  111. const startRun = () => {
  112. console.log(isRunning, totalRunAngle.value)
  113. // 设置动效
  114. styleObj.value = `${bgColor} transform: rotate(${totalRunAngle.value}deg); transition: all 4s ease;`
  115. setTimeout(stopRun, 4000)
  116. }
  117. const start = () => {
  118. if (!isRunning) {
  119. isRunning = true
  120. console.log('开始抽奖,后台请求中奖奖品')
  121. setTimeout(() => {
  122. // 请求返回的奖品编号 这里使用随机数
  123. prizeId = getRandomNum()
  124. console.log('中奖ID>>>', prizeId, prizeList[prizeId])
  125. }, 2000)
  126. startRun()
  127. }
  128. }
  129. </script>
  130. <style lang="scss">
  131. .container {
  132. position: relative;
  133. width: 90vw;
  134. height: 90vw;
  135. margin: 20px auto;
  136. border: 10px solid #98d3fc;
  137. border-radius: 50%;
  138. }
  139. .prize-list {
  140. box-sizing: border-box;
  141. width: 100%;
  142. height: 100%;
  143. overflow: hidden;
  144. border-radius: 50%;
  145. // 使用outline代替border可以省很多定位的问题
  146. // outline: 10px solid #98d3fc;
  147. }
  148. .prize-item {
  149. position: absolute;
  150. top: 0;
  151. right: 0;
  152. left: 0;
  153. display: flex;
  154. flex-direction: column;
  155. margin: auto;
  156. // border: 2px solid red;
  157. }
  158. .prize-item .gift-img {
  159. display: block;
  160. width: 30%;
  161. height: 20%;
  162. margin: 20px auto 10px;
  163. border-radius: 50%;
  164. }
  165. .prize-item .gift-name {
  166. font-size: 12px;
  167. line-height: 20px;
  168. color: #fff;
  169. text-align: center;
  170. }
  171. .lottery-btn {
  172. position: absolute;
  173. top: 50%;
  174. left: 50%;
  175. width: 80px;
  176. height: 96px;
  177. margin: auto;
  178. cursor: pointer;
  179. background: url('https://cip-shopping-page-0eysug01066a9e-1302818703.tcloudbaseapp.com/fly/lottery-prize/btn-enable.png')
  180. no-repeat center / 100% 100%;
  181. transform: translate(-50%, -50%);
  182. }
  183. </style>