slot-machine.vue 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <template>
  2. <view v-if="isShow" class="lucky-box" :style="{ width: boxWidth + 'px', height: boxHeight + 'px' }">
  3. <canvas
  4. type="2d"
  5. id="slot-machine"
  6. canvas-id="slot-machine"
  7. :style="{ width: boxWidth + 'px', height: boxHeight + 'px' }"
  8. ></canvas>
  9. <image
  10. v-if="imgSrc"
  11. :src="imgSrc"
  12. @load="myLucky.clearCanvas()"
  13. :style="{ width: boxWidth + 'px', height: boxHeight + 'px' }"
  14. ></image>
  15. <!-- #ifndef H5 -->
  16. <view v-if="myLucky">
  17. <div class="lucky-imgs">
  18. <div v-for="(block, index) in blocks" :key="index">
  19. <div v-if="block.imgs">
  20. <image v-for="(img, i) in block.imgs" :key="i" :src="img.src" @load="e => imgBindload(e, 'blocks', index, i)"></image>
  21. </div>
  22. </div>
  23. </div>
  24. <div class="lucky-imgs">
  25. <div v-for="(prize, index) in prizes" :key="index">
  26. <div v-if="prize.imgs">
  27. <image v-for="(img, i) in prize.imgs" :key="i" :src="img.src" @load="e => imgBindload(e, 'prizes', index, i)"></image>
  28. </div>
  29. </div>
  30. </div>
  31. </view>
  32. <!-- #endif -->
  33. </view>
  34. </template>
  35. <script>
  36. import { changeUnits, resolveImage, getImage } from './utils.js'
  37. import { SlotMachine } from '../../lucky-canvas'
  38. export default {
  39. name: 'slot-machine',
  40. data () {
  41. return {
  42. imgSrc: '',
  43. myLucky: null,
  44. canvas: null,
  45. isShow: false,
  46. boxWidth: 100,
  47. boxHeight: 100,
  48. btnWidth: 0,
  49. btnHeight: 0,
  50. dpr: 1,
  51. }
  52. },
  53. props: {
  54. width: {
  55. type: String,
  56. default: '600rpx'
  57. },
  58. height: {
  59. type: String,
  60. default: '600rpx'
  61. },
  62. blocks: {
  63. type: Array,
  64. default: () => []
  65. },
  66. prizes: {
  67. type: Array,
  68. default: () => []
  69. },
  70. slots: {
  71. type: Array,
  72. default: () => []
  73. },
  74. defaultConfig: {
  75. type: Object,
  76. default: () => ({})
  77. },
  78. defaultStyle: {
  79. type: Object,
  80. default: () => ({})
  81. },
  82. },
  83. mounted () {
  84. // #ifndef APP-PLUS
  85. this.initLucky()
  86. // #endif
  87. },
  88. watch: {
  89. blocks (newData) {
  90. this.myLucky && (this.myLucky.blocks = newData)
  91. },
  92. prizes (newData) {
  93. this.myLucky && (this.myLucky.prizes = newData)
  94. },
  95. slots (newData) {
  96. this.myLucky && (this.myLucky.slots = newData)
  97. },
  98. defaultStyle (newData) {
  99. this.myLucky && (this.myLucky.defaultStyle = newData)
  100. },
  101. defaultConfig (newData) {
  102. this.myLucky && (this.myLucky.defaultConfig = newData)
  103. },
  104. },
  105. methods: {
  106. async imgBindload (res, name, index, i) {
  107. const img = this[name][index].imgs[i]
  108. resolveImage(img, this.canvas)
  109. },
  110. getImage () {
  111. return getImage.call(this, 'slot-machine', this.canvas)
  112. },
  113. hideCanvas () {
  114. // #ifdef MP
  115. this.getImage().then(res => {
  116. this.imgSrc = res.tempFilePath
  117. })
  118. // #endif
  119. },
  120. initLucky () {
  121. this.boxWidth = changeUnits(this.width)
  122. this.boxHeight = changeUnits(this.height)
  123. this.isShow = true
  124. // 某些情况下获取不到 canvas
  125. this.$nextTick(() => {
  126. setTimeout(() => {
  127. this.draw()
  128. })
  129. })
  130. },
  131. draw () {
  132. const _this = this
  133. uni.createSelectorQuery().in(this).select('#slot-machine').fields({
  134. node: true, size: true
  135. }).exec((res) => {
  136. // #ifdef H5
  137. res[0].node = document.querySelector('#slot-machine canvas')
  138. // #endif
  139. if (!res[0] || !res[0].node) return console.error('lucky-canvas 获取不到 canvas 标签')
  140. const { node, width, height } = res[0]
  141. const canvas = this.canvas = node
  142. const ctx = this.ctx = canvas.getContext('2d')
  143. const dpr = this.dpr = uni.getSystemInfoSync().pixelRatio
  144. // #ifndef H5
  145. canvas.width = width * dpr
  146. canvas.height = height * dpr
  147. ctx.scale(dpr, dpr)
  148. // #endif
  149. const myLucky = this.myLucky = new SlotMachine({
  150. // #ifdef H5
  151. flag: 'WEB',
  152. // #endif
  153. // #ifdef MP
  154. flag: 'MP-WX',
  155. // #endif
  156. ctx,
  157. dpr,
  158. // #ifndef H5
  159. offscreenCanvas: uni.createOffscreenCanvas({ type: '2d' }),
  160. // #endif
  161. setTimeout,
  162. clearTimeout,
  163. setInterval,
  164. clearInterval,
  165. // #ifdef H5
  166. rAF: requestAnimationFrame,
  167. // #endif
  168. unitFunc: (num, unit) => changeUnits(num + unit),
  169. afterStart: () => {
  170. this.imgSrc = ''
  171. },
  172. }, {
  173. ...this.$props,
  174. width,
  175. height,
  176. end: (...rest) => {
  177. this.$emit('end', ...rest)
  178. this.hideCanvas()
  179. },
  180. })
  181. })
  182. },
  183. init () {
  184. this.myLucky.init()
  185. },
  186. play (...rest) {
  187. this.myLucky.play(...rest)
  188. },
  189. stop (...rest) {
  190. this.myLucky.stop(...rest)
  191. },
  192. },
  193. }
  194. </script>
  195. <style scoped>
  196. .lucky-box {
  197. position: relative;
  198. overflow: hidden;
  199. margin: 0 auto;
  200. }
  201. .lucky-box canvas {
  202. position: absolute;
  203. pointer-events: none;
  204. left: 0;
  205. top: 0;
  206. }
  207. .lucky-imgs {
  208. width: 0;
  209. height: 0;
  210. visibility: hidden;
  211. }
  212. </style>