l-dialer.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <template>
  2. <view class="l-dialer" :style="getStyle">
  3. <view class="l-dialer__inner" :style="getDialStyle">
  4. <view class="l-dialer__inner-border" v-if="$slots.border">
  5. <slot name="border"/>
  6. </view>
  7. <view class="l-dialer__inner-wrap" :style="styleOpt.borderColor && (' border: 1rpx solid ' + styleOpt.borderColor)">
  8. <view class="l-dialer__inner-item" v-for="(item, index) in prizeList" :key="index" :style="[getRotateAngle(index)]">
  9. <view class="l-dialer__inner-content" :style="[getCorrectAngle(index)]">
  10. <slot v-if="$slots.prize" name="prize" :item="item" :even="index % 2"></slot>
  11. <block v-else>
  12. <view class="l-dialer__inner-name" :style="[{fontSize: styleOpt.fontSize, color: styleOpt.color}]">{{ item.name }}</view>
  13. <image class="l-dialer__inner-img" :src="item.img"></image>
  14. </block>
  15. </view>
  16. </view>
  17. </view>
  18. </view>
  19. <view class="l-dialer__pointer" :style="pointerStyle" >
  20. <slot v-if="$slots && $slots.pointer" name="pointer"/>
  21. <image
  22. v-else
  23. :class="!isTurnIng ? 'heart': ''"
  24. src="/uni_modules/lime-dialer/static/turnable_btn.png"
  25. style="width: 100%"
  26. mode="widthFix"
  27. @tap="$emit('click')"
  28. />
  29. </view>
  30. </view>
  31. </template>
  32. <script>
  33. // import {addUnit} from '@/uni_modules/lime-shared/addUnit'
  34. // import {sleep} from '@/uni_modules/lime-shared/sleep'
  35. export default {
  36. name: 'l-dialer',
  37. emits: ['click', 'done'],
  38. props: {
  39. size: {
  40. type: [String, Number],
  41. default: 300
  42. },
  43. prizeList: {
  44. type: Array
  45. },
  46. turns: {
  47. type: Number,
  48. default: 10
  49. },
  50. duration: {
  51. type: Number,
  52. default: 3
  53. },
  54. styleOpt: {
  55. type: Object,
  56. default: () => ({
  57. // 每一块扇形的背景色,默认值,可通过父组件来改变
  58. // $primary-1 $primary-2
  59. prizeBgColors: ['#fff0a3', '#fffce6'],
  60. // 每一块扇形的外边框颜色,默认值,可通过父组件来改变
  61. // primary-4
  62. borderColor: '#ffd752',
  63. })
  64. },
  65. customStyle: {
  66. type: String,
  67. },
  68. dialStyle: {
  69. type: String,
  70. },
  71. pointerStyle: {
  72. type: String,
  73. default: `width: 30%`
  74. }
  75. },
  76. data() {
  77. return {
  78. // 开始转动的角度
  79. startRotateDegree: 0,
  80. // 设置指针默认指向的位置,现在是默认指向2个扇形之间的边线上
  81. rotateAngle: 0,
  82. rotateTransition: '',
  83. isTurnIng: false,
  84. };
  85. },
  86. computed: {
  87. getStyleOpt() {
  88. const style = {
  89. // 每一块扇形的背景色,默认值,可通过父组件来改变
  90. prizeBgColors: ['#fff0a3', '#fffce6'],
  91. // 每一块扇形的外边框颜色,默认值,可通过父组件来改变
  92. borderColor: '#ffd752',
  93. }
  94. return Object.assign(style, this.styleOpt)
  95. },
  96. getRotateAngle() {
  97. return index => {
  98. const style = {
  99. transform: `rotate(${(360 / this.prizeList.length) * index}deg) skewX(0deg) skewY(${360 / this.prizeList.length - 90}deg)`,
  100. backgroundColor: `${this.getStyleOpt.prizeBgColors[index % this.getStyleOpt.prizeBgColors.length]}`,
  101. border: `${this.getStyleOpt.borderColor && '1rpx solid ' + this.getStyleOpt.borderColor }`
  102. }
  103. if(this.prizeList.length == 2) {
  104. style['transform'] = index == 0 ? 0 : `rotate(270deg)` //`rotate(${(360 / this.prizeList.length) * index}deg)`
  105. style['top'] = 0
  106. }
  107. return style
  108. // return {
  109. // transform: `rotate(${(360 / this.prizeList.length) * index}deg) skewX(0deg) skewY(${360 / this.prizeList.length - 90}deg)`,
  110. // backgroundColor: `${this.styleOpt.prizeBgColors[index % this.styleOpt.prizeBgColors.length]}`,
  111. // border: `${this.styleOpt.borderColor && '1rpx solid ' + this.styleOpt.borderColor }`
  112. // }
  113. };
  114. },
  115. getCorrectAngle() {
  116. return index => {
  117. const style = {
  118. transform: `skewY(${90 - 360 / this.prizeList.length}deg) skewX(0deg) rotate(${180 / this.prizeList.length}deg)`
  119. }
  120. if(this.prizeList.length == 2){
  121. if(index == 0) {
  122. style['transform'] = `rotate(90deg)`
  123. style['bottom'] = 0
  124. } else {
  125. style['transform'] = `rotate(0deg)`
  126. style['left'] = 0
  127. style['bottom'] = '-50%'
  128. }
  129. }
  130. return style
  131. };
  132. },
  133. getStyle() {
  134. let { size, customStyle } = this;
  135. //addUnit(size)//
  136. size = /\d$/.test(size) ? size + 'px' : size;
  137. return `width: ${size}; height: ${size}; ${customStyle}`;
  138. },
  139. getDialStyle() {
  140. return `
  141. padding: ${this.getStyleOpt.padding};
  142. transform: ${this.rotateAngle};
  143. transition: ${this.rotateTransition};
  144. ${this.dialStyle}
  145. `;
  146. }
  147. },
  148. methods: {
  149. // 转动起来
  150. run(index) {
  151. if(this.isTurnIng) return
  152. const duration = this.duration;
  153. const length = this.prizeList.length
  154. const rotateAngle = this.startRotateDegree + this.turns * 360 + 360 - (180 / length + (360 / length) * index) - (this.startRotateDegree % 360);
  155. this.startRotateDegree = rotateAngle;
  156. this.rotateAngle = `rotate(${rotateAngle}deg)`;
  157. this.rotateTransition = `transform ${duration}s cubic-bezier(0.250, 0.460, 0.455, 0.995)`;
  158. this.isTurnIng = true
  159. // sleep(duration * 1000 + 500).then(() => {
  160. // this.$emit('done', index);
  161. // this.isTurnIng = false
  162. // })
  163. setTimeout(() => {
  164. this.$emit('done', index);
  165. this.isTurnIng = false
  166. }, duration * 1000 + 500);
  167. }
  168. }
  169. };
  170. </script>
  171. <style lang="scss" scoped>
  172. @import './index';
  173. </style>