前言
关于关于【SSD系列】:
前端一些有意思的内容,旨在3-10分钟里, 500-1500字,有所获,又不为所累。
效果演示
PC端
模拟移动端
源码
- 包含封装库
- 包含UI
抽奖简析
抽奖嘛,简单说就是障眼法。 前前后后的动画都是增强一些体验,寻求一点刺激罢了,幻想自己能成为那个大奖获得者。
常见表现形式
常见的抽奖表现有两种,九宫格和转盘,转盘又有转动指针和转动转盘两种。 从实现难度上来说, 转盘大于九宫格。
一般的实现方式
- 九宫格
间隔的设置背景色或者蒙层,越往后间隔越大。
- 转盘
- 纯脚本控制:每个一段时间,转动转盘或者指针,越往后,转动越少。
- css动画: 提前计算旋转角度好,配合css3, 利用好贝塞尔函数,梭哈。
一般逻辑处理
- 动画先行
就是先执行动画,期间去获取结果,然后决定定格在何处。
- 结果先行
先获取结果,然后启动动画。
掘金站点技术浅析
这里就客串分析下掘金的技术栈,推荐一款 BuiltWith Technology Profiler的chrome创建,其能分析出网站的采用哪些技术构建。 我们一看看看掘金的。
看看DOm节点熟悉的__nuxt
和 data-v
, 还真是那么回事。
掘金抽奖简析
掘金的抽奖属于典型的九宫格,中间是抽奖的按钮。
布局
典型的flex布局,九个格子,九个turntable-item
div,抽奖按钮采用单独的lottery
样式标记。
动画先行还是结果先行?
抽奖接口是https://api.juejin.cn/growth_api/v1/lottery/draw
,我们打开控制面板, Network板块,输入draw
过滤请请求。
执行一次,然后block抽奖请求。
再次执行,可以明显的看到先执行了动画,所以我推断是动画先行,至于真相,他重要吗?不重要,反正我也抽不中!!!!!!
实现思路
我们采用动画先行方案,先启动动画,中途请求结果,得到结果后,执行命中动画。
基本思路
1. 编号
0-n
个坑位,九宫格的话,就是0-7
个坑位,坑位的东西可以重复。
2.启动动画
匀速的切换格子,同时请求服务接口。
3. 中奖动画
收到结果后,计算出命中奖品的编号,并执行减速逻辑。
分离逻辑
基本思路就是这样子的,为了通用性,我们需要多思考一些,抽奖重要的是逻辑,表面的形式重要吗? 其实并不太重要,所以我们这里把抽奖逻辑封装,提供可变性,并对外提供事件通知。
可变性
可变性一般是通过参数和对外暴露方法来实现的,我们也不例外。
- 格子数,不仅仅是九宫格,10宫格,12宫格都支持
- 起始位置,不一定是从0开始
- 起始的时间间隔,之后会越来越慢
- 至少转动的次数, 如果接口太快,可能感觉没开始就结束了。
- 得到结果后,我们的减速动画逻辑,应该是内置,同时可以被覆写。
事件通知
整个过程可能存在的事件:
- onStart: // 当开始
- onUpdate: // 旋转一次
- onEnded: // 结束
- onError: // 异常
我们把这些整个起来, 大概就是这个样子了,都很简单。
var defaultOption = { startIndex: 0, // 初始位置 pits: 8, // 格子数 interval: 100, // 初始间隔 rate: 2.5, // 系数 cycle: 5, //转动基本次数:即至少需要转动多少次再进入抽奖环节 getInterval: null // 自定义旋转间隔函数 //onStart: null, // 当开始 //onUpdate: null, // 旋转一次 //onEnded: null, // 结束 //onError: null // 异常, 比如转动次数已经达到设定值, 但是没有设置奖项 }; 复制代码
使用代码
工具方法
先封装两个添加方法,一个添加选中的class,一个删除选中的class。
function removeChosenClass() { var el = lotteryEl.querySelector('.turntable-item.chosen'); if (el) { el.classList.remove('chosen'); } } function addChosenClass(index){ lotteryEl.querySelector('.turntable-item.turntable-item-' + index).classList.add('chosen'); } 复制代码
实例化
Lottery是我们封装的逻辑类。
var options = { }; var lottery = new Lottery(options); 复制代码
注册启动事件和模拟中奖
4号坑位是大奖
var btnStart = document.querySelector(".turntable-box .turntable-item.lottery"); btnStart.addEventListener('click', function () { lottery.start(); setTimeout(() => { setPrize(); }, 800) }) function setPrize() { lottery.setPrize([4]) // 4号坑位是大奖 } 复制代码
监听抽奖事件
lottery.onUpdate = function (ins, index, times) { removeChosenClass(); addChosenClass(index); } lottery.onEnded = function (ins, index, prizeIndexes) { removeChosenClass(); addChosenClass(index); setTimeout(function () { dialogEl.classList.remove("hide"); }, 500) } 复制代码
到此为止,使用代码完毕,与框架无关。
逻辑库封装
逻辑库的完整代码位于 抽奖逻辑Lottery.js , 我就不全贴出来,不然违背我500-1500字的原则了,就贴一张简单的属性图吧。
小结
是不是很简单,一切都看起来没那么难。
写在最后
不忘初衷,【SSD系列】,3-5分钟,500-1000字,有所得,而不为所累,如果你觉得不错,你的一赞一评就是我前行的最大动力。