大家好,我是HoMeTown。
中秋节
快到了,掘金社区一如既往十分贴心的在这种有意义节日里推出了社区周边的礼盒,像之前的端午粽子礼盒,这次推出了中秋月饼礼盒。
满打满算,从今年的端午礼盒到现在的中秋礼盒,我最起码攒了有30w+的矿石了(海底+签到+Bug+升级奖励),但是当我打开我的余额,他却瘪成这样:
矿石去哪儿了?
矿石在这:
掘金一直保持初心,逢年过节推出节日性礼盒。
我也是,逢年过节疯狂的点击抽奖按钮,然而 一如既往的梭哈,一如既往的打水漂。
你不是欺负老实人吗?--《让子弹飞》
在沸点看到有人抽中了,然后咱也不知道从哪儿来的自信,就觉得自己说不定也能中,想靠运气试试能不能搞一个,紧接着脑袋一热,小手一点。辛辛苦苦攒的钻石全部拜拜👋🏻。
有人说这叫赌徒心理。
借此机会,我也去搜了一下什么叫赌徒心理
,同时分享给大家:
(1)只想碰运气发横财,不愿意劳动致富、创业致富;
(2)敢于孤注一掷,铤而走险,甚至不惜以生命为代价;
(3)为了达到目的,可以不择手段。
但是我感觉我这应该算不上赌徒心理
?撑死应该沾点边儿吧(ps. 其实差不多)。
本着不想花矿石,还想玩儿的目的,我决定用Vue3自己做一个和它一样的抽奖转盘。
公平!公平!还是TMD公平!--《让子弹飞》
首先是排版与样式,这块没什么好说的,简单先划分一下结构:
定义结构:
lottery-container
转盘容器mask
遮罩层model
模态层btn1
单抽btn2
十连抽border
4条边框goods-container
商品容器turntable-wrap
抽奖盒子cost-wrap
操作盒子result-container
抽奖结果容器关键点在于实现的js逻辑,首先,类似这样的js逻辑,本应该放在服务端,而不应该在客户端进行处理,此处只是demo,有不对的地方望指正:
点击开始抽奖的事件:
function onStart() { // 设置定时器,每隔20ms做一次update操作,以达到动态切换active的目的
let interval = setInterval(() => { // 此处没有用函数 winPrize是因为20ms的频率开销太大,所以仅做mock,在最后的时候更新即可
curActive.value = Math.floor(Math.random() * 9)
}, 20) // 设置延时器,结束定时操作
let timer = setTimeout(() => { // 拿到最后中奖的索引
curActive.value = winPrize(probArr.value) // 弹出结果层、清楚定时器 & 延时器
showResult.value = true
clearInterval(interval) clearTimeout(timer)
}, 2000);
}
中奖结果的概率计算,这里相对上面的逻辑来说可能比较复杂一点,但是我的这个也是比较简单版本的,我的思路是分为以下几步:
const goods = [
{ probability: 10, name: '随机矿石', },
{ probability: 10, name: '随机矿石', },
{ probability: 10, name: '随机矿石', },
{ probability: 10, name: '随机矿石', },
{ probability: 10, name: '随机矿石', },
{ probability: 50, name: 'Switch', },
]// 对应各个奖项的概率,总和为100const probArr = computed(() => { return goods.map(item => item.probability)
})
function winPrize(arr) { let sum = eval(arr.join("+")); // 获取总概率区间
for (let i = 0; i < arr.length; i++) { let random = parseInt(Math.random() * sum); // 获取 0-总概率区间的一个随随机整数
if (random < arr[i]) { return i; //如果在当前的概率范围内,得到的就是当前概率
} else {
sum -= arr[i]; //否则减去当前的概率范围,进入下一轮循环
}
}
}
十连抽的逻辑也是相同的,只是将最后的结果从单个下标换成下标的集合。
https://github.com/HoMeTownSoCool/vue3-juejin-lottery