最近掘金的抽奖永远都是 66矿石 和 Bug,实在是对不起自己,为了满足自己不要再抽中 66矿石 和 Bug,决定自己写一个抽奖列表,抽奖,过程绝对公平公正公开有效
让我们先来看下玩法(怎么又是66矿石)
文末笔者将整个抽奖流程都抽离出封装成了对应的Vue
版本组件,方便大家使用(本文是用Vue
版本作为例子)
这里来看下怎么写一个不再是矿石和Bug的抽奖
第一步:正反面卡片
先生成掘金抽奖模拟的卡牌数据
const list = ref([
{
name: "66矿石",
img:
"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/32ed6a7619934144882d841761b63d3c~tplv-k3u1fbpfcp-no-mark:0:0:0:0.awebp",
},
...
{
name: "Switch",
img: 'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4decbd721b2b48098a1ecf879cfca677~tplv-k3u1fbpfcp-no-mark:0:0:0:0.awebp'
},
]);
由于需要做成组件,我们需要通过
Vue2::props.sync="list"
Vue3:v-model:list="list"
修改父组件传来的list
,为每一个卡牌添加turn
属性,为之后通过先后顺序给点中的奖牌先翻奖动效添加属性
我们需要先把正反面的样式写好
样式这里不作简述
需要注意的是正、反两面用的是不同的样式
通过transform: rotateY(180deg)
和transform: rotateY(0)
来控制卡牌的正反面,且给对应的正反面写相应的样式,这里就不放代码了,有兴趣的可直接上github查看源码
得到正面卡牌
和反面卡牌
第二步:翻转卡牌
完成正反面样式编写后,我们需要添加一个function
来控制翻转所有卡牌样式
/**
* 翻转所有卡牌
*/
const turnAllPrizes = (turn: boolean) => {
const list = props.list;
const newList = list.map((item: IPrize) => {
item.turn = turn;
return item;
});
context.emit("update:list", newList);
};
第三步:居中洗牌回位
洗牌
首先我们需要将所有的卡牌居中
这里我们用 scss
将样式写好
通过scss
的计算方法,我们很快就能写好卡片居中的样式
通过transition
属性,使我们添加对应移动的class
的时候会默认添加过渡效果
@use "sass:math";
$card-height: 220px;
$half-width: 50;
@function moveTranslateY($i) {
@return if($i < 4, math.div($card-height, 2), -(math.div($card-height, 2)));
}
@function moveTranslateX($i) {
@return if(
$i < 4,
(calc(#{$half-width - $i * 25}vw - 50%)),
(calc(#{$half-width - ($i - 4) * 25}vw - 50%))
);
}
@for $i from 0 through 7 {
.move-#{$i} {
transform: translate(moveTranslateX($i), moveTranslateY($i));
}
}
回位
回位也很简单,只需要把对应的class
移除即可
第四步:翻牌
思路也很简单,点击对应的卡牌的时候,将其turn
属性修改回false
,500ms后再将其他所有的卡牌统一翻转
/**
* 抽奖
*/
const lottery = debounce(
(click: number) => {
// 执行动画时,不许点击
if (lock) return;
click_index.value = click;
dealPrizes();
},
500,
{
leading: true,
trailing: false,
}
);
/**
* 处理奖品
*/
const dealPrizes = () => {
const list = props.list;
// 点击的 index 先翻转
list[click_index.value].turn = false;
context.emit("update:list", list);
// 其余的 0.5s 后翻转
setTimeout(() => {
turnAllPrizes(false);
turning.value = !turning.value;
}, 500);
isFirst.value = false;
// 去掉一次抽奖机会
context.emit("update:drawNumber", props.drawNumber - 1);
};
这样子就实现完成了,其实实现的流程不算复杂,更多的是思路和动画效果的流程思考。
Demo
本文只展示了部分代码,Demo示例已上传至github
Vue3
版本:vue-flop-draw
其他
看得不过瘾?这里还有别的文章