在 Github 上面搜索 “lottery”,发现类似的项目挺多的,有 Electron 实现的,可以打包成 exe,也有原生 js 实现的,浏览器打开。
这次是用 Vue 做了一个编号抽奖,一个转盘抽奖,放在一起,练手。
预览:http://lottery.imaegoo.com/
编号抽奖
编号抽奖实现起来非常简单,存一个号码池,存一个抽奖历史,从号码池中过滤掉已中奖的号码,从剩下的号码随机出一个就可以了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| <template> <div class="lottery"> <div class="current">{{ current }}</div> <button class="button is-large is-warning" v-if="!timer" @click="start">开始</button> <button class="button is-large is-danger" v-if="timer" @click="stop">停</button> <table class="table" v-if="history.length > 0"> <thead> <tr> <th>轮次</th> <th>中奖号码</th> </tr> </thead> <tbody> <tr v-for="(item, index) in history" :key="index"> <td>{{ index + 1 }}</td> <td>{{ item }}</td> </tr> </tbody> </table> </div> </template>
<script> export default { data () { return { numbers: [], current: '', timer: null, history: [] } }, computed: { neverWin () { return this.numbers.filter((item) => !this.history.some((historyItem) => historyItem === item)) } }, methods: { random (minNum, maxNum) { return parseInt(Math.random() * (maxNum - minNum + 1) + minNum) }, start () { if (this.neverWin.length < 1) { alert('所有人都已中过奖! 请到设置清空中奖纪录!') return } this.timer = setInterval(this.refresh, 100) }, stop () { clearInterval(this.timer) this.timer = null this.saveHistory() }, refresh () { let next do { next = this.neverWin[this.random(0, this.neverWin.length - 1)] } while (this.current === next) this.current = next }, saveHistory () { this.history.push(this.current) localStorage.setItem('history', JSON.stringify(this.history)) }, readNumbers () { const numStr = localStorage.getItem("numbers") if (numStr) this.numbers = numStr.split('\n').filter((item) => !!item) if (this.numbers.length === 0) { alert('抽奖池为空! 请到右上角设置中添加!') this.numbers = ['11', '22', '33', '44', '55', '66', '77', '88', '99'] } }, readHistory () { const history = localStorage.getItem("history") if (history) this.history = JSON.parse(history) } }, mounted () { this.readNumbers() this.readHistory() this.current = this.numbers[0].split('').map(() => '*').join('') } } </script>
|
转盘抽奖
转盘抽奖稍微复杂一点:
- 随机抽一个目标奖项
- 计算得出到这个奖项的转动角度(这里的角度我也是在区间中随机取,看上去更真实)
- 加上(360° × 转多少圈)
- 绑定到转盘图片的
transform
上 - 设置旋转动画
transition: transform 5s;
做完之后发现也不是很难。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
| <template> <div class="rotate"> <div class="arrow"> <img class="wheel" src="../assets/wheel.png" :style="{transform: `rotate(${currentAngle}deg)`}" /> <div class="pointer" @click="startArrow"></div> </div> <div class="text" v-if="currentAward">{{ currentAward }}</div> </div> </template>
<script> const awards = [ '侯校长发红包', '工作日不扣工资,休息一天', '与黄书记共进晚餐', '工作日不扣工资,休息半天', '教研组最美(最帅)的人请喝奶茶', '跟校长们合张影' ] export default { props: { msg: String }, data() { return { currentAngle: 0, times: 0, currentAward: '等待抽奖' } }, methods: { startArrow() { if (this.currentAward === '正在抽奖') return let award = this.getAward() this.getAngle(award) this.setCurrentAward(award) }, getAward() { let randomNum = Math.random() if (randomNum < 0.3) { return 0 } else if (randomNum < 0.4) { return 1 } else if (randomNum < 0.5) { return 2 } else if (randomNum < 0.6) { return 3 } else if (randomNum < 0.75) { return 4 } else if (randomNum <= 1) { return 5 } }, getAngle(award) { this.times++ let max = (award + 1) * 60 let min = award * 60 let angle = parseInt(Math.random() * (max - min + 1) + min, 10) this.currentAngle = 360 * (this.times * 7) + angle }, setCurrentAward(award) { this.currentAward = '正在抽奖' setTimeout(() => { this.currentAward = `恭喜中奖:${awards[award]}` }, 5000) } } } </script>
<style scoped> .arrow { position: relative; } .wheel { transition: transform 5s; } .pointer { background-repeat: no-repeat; background-position: center; background-image: url('../assets/arrow.png'); content: ''; top: 0; left: 0; right: 0; bottom: 0; position: absolute; } .text { margin-top: 20px; font-size: 26px; font-weight: bold; } </style>
|
指针 arrow.png
和转盘 wheel.png
两张图片可以在 https://github.com/imaegoo/lottery/tree/zhengzhou/src/assets 找到。
路由
反正只有4个页面,直接自己写一个 tab 切换,没有引入 vue-router。
UI框架
功能太简单也用不到,只用了一个 Bulma。
啊~ 轻量又好用的 Bulma~
总结
源码放在了 https://github.com/imaegoo/lottery 上面。
设计、切图、编码、测试总共花了6小时,嗯,挺简单的。