手摸手。完成一个H5 抽奖功能
要完成一个这样的抽奖功能
构思
- 奖励物品是通过接口获取的(img)
- 奖励结果是通过接口获取的(id)
- 抽奖的动画需要由慢到快再到慢
- 抽奖转动时间不能太短
- 抽奖结束需要回调
- 业务代码和功能代码要分离
先完成一个 UI
使用 flex 来布局,easy,当 curGameIdx 等于当前奖品 index 时高亮
html
<div class="game-box">
<template
v-for="(val, idx) of boundList">
<div v-if="idx == 4" class="game-item game-begin"
:key="idx"
@click="beginGame">
开始游戏
</div>
<div v-else :key="idx"
class="game-item"
:class="{
active: idx === curGameIdx
}">
{{val}}
</div>
</template>
</div>
css
.game-box {
display: flex;
flex-wrap: wrap;
text-align: center;
.game-item {
width: 1.25rem;
height: 0.3rem;
background: yellow;
border: 1px solid transparent;
transition: all 0.2s;
&.game-begin {
background: transparent;
}
&.active {
border: 1px solid black;
}
}
}
效果图
开始做动画效果
新建一个 Game 的 class,有有个 run 方法和 finish 方法
开始运行
动画的速度是变化的,使用 requestAnimationFrame 和 setInterval 有点不妥,所以:可以使用 setTimeout + speed 参数 来控制动画的速度。
class Game {
constructor(idx) {
this.idx = idx;
this.speed = 400;
}
addIdx(){
}
speedControl() {
}
finish() {
}
run(cb) {
this.speedControl();
setTimeout(() => {
this.addIdx();
!this.isFinish && this.run(cb);
}, this.speed);
}
}
结束运行
收到结束运行的通知时,需要先做减速动画,然后再停止在对应的 num,然后调用回调函数,所以先暂存结束回调和结束点,并将动画设置为减速。
finish(num, finishCb) {
this.oil = false;
this.endIdx = num;
this.finishCb = finishCb;
}
速度的控制
- 默认速度为加速(
this.oil = true)通过是否达到预期速度来停止加速,当减速时同理。 - 为达到缓动结束效果,所以结束时间通过:到达最小速度 且 到达结束位置。
speedUp() {
this.speed -= 60;
}
speedDown() {
this.speed += 200;
}
speedControl() {
if (this.speed > this.Max_Speed) {
if (this.oil) {
this.speedUp();
}
}
if (!this.oil) {
if (this.speed < this.Min_Speed) {
this.speedDown();
} else if (this.endIdx === this.idx) {
this.isFinish = true;
typeof this.finishCb === 'function' && this.finishCb();
}
}
}
index 矫正
此时,上面 UI 是通过 v-for + flex 展示的,而动画的执行是转圈,所以需要矫正 index
更改上面 addIdx 方法,矫正 index,并将 ++index 取余
constructor(idx) {
this.idx = idx;
this.speed = 400;
this.order = null;
this.Order_List = [0,1,2,5,8,7,6,3];
this.Game_Box_Num = 8;
}
addIdx() {
this.idx = (++this.idx % this.Game_Box_Num);
this.order = this.Order_List[this.idx];
}
活动代码与业务代码互动
将需要交互的函数传递给 Game 的实例即可
// vue 代码
methods: {
updateGameIdx(order) {
this.curGameIdx = order;
},
gameFinish() {
this.playing = false;
console.log(this.curGameIdx, 'curGameIdx')
},
beginGame() {
if (this.playing) return;
this.playing = true;
this.curGameIdx = 0;
const game = new Game(this.curGameIdx);
game.run(this.updateGameIdx);
// 通过请求终止
setTimeout(() => {
game.finish(2, this.gameFinish)
}, 3000);
}
}
最后附上完整 Game 代码:
class Game {
constructor(idx) {
this.idx = idx;
this.speed = 400;
this.oil = true;
this.isFinish = false;
this.endIdx = null;
this.finishCb = function() {}
// 常量
this.Max_Speed = 100;
this.Min_Speed = 500;
this.Order_List = [0,1,2,5,8,7,6,3];
this.Game_Box_Num = 8;
}
speedUp() {
this.speed -= 60;
}
speedDown() {
this.speed += 200;
}
speedControl() {
if (this.speed > this.Max_Speed) {
if (this.oil) {
this.speedUp();
}
}
if (!this.oil) {
if (this.speed < this.Min_Speed) {
this.speedDown();
} else if (this.endIdx === this.idx) {
this.isFinish = true;
typeof this.finishCb === 'function' && this.finishCb();
}
}
}
finish(num, finishCb) {
this.oil = false;
this.endIdx = num;
this.finishCb = finishCb;
}
addIdx() {
this.idx = (++this.idx % this.Game_Box_Num);
}
run(cb) {
this.speedControl();
typeof cb === 'function' && cb(this.Order_List[this.idx]);
setTimeout(() => {
this.addIdx();
!this.isFinish && this.run(cb);
}, this.speed);
}
}
export default Game;
大致效果
主要功能已经实现,想漂亮点再改改 CSS 就好了,动画时间也需要再调试。(避嫌,具体结果不能提供 - -。)
最后
译者写了一个 React + Hooks 的 UI 库,方便大家学习和使用,
欢迎关注公众号「前端进阶课」认真学前端,一起进阶。
手摸手。完成一个H5 抽奖功能的更多相关文章
- 【转】手摸手,带你用vue撸后台 系列四(vueAdmin 一个极简的后台基础模板)
前言 做这个 vueAdmin-template 的主要原因是: vue-element-admin 这个项目的初衷是一个vue的管理后台集成方案,把平时用到的一些组件或者经验分享给大家,同时它也在不 ...
- 浅谈Java中的Condition条件队列,手摸手带你实现一个阻塞队列!
条件队列是什么?可能很多人和我一样答不出来,不过今天终于搞清楚了! 什么是条件队列 条件队列:当某个线程调用了wait方法,或者通过Condition对象调用了await相关方法,线程就会进入阻塞状态 ...
- 【手摸手,带你搭建前后端分离商城系统】01 搭建基本代码框架、生成一个基本API
[手摸手,带你搭建前后端分离商城系统]01 搭建基本代码框架.生成一个基本API 通过本教程的学习,将带你从零搭建一个商城系统. 当然,这个商城涵盖了很多流行的知识点和技术核心 我可以学习到什么? S ...
- 手摸手教你微信小程序开发之自定义组件
前言 相信大家在开发小程序时会遇到某个功能多次使用的情况,比如弹出框.这个时候大家首先想到的是组件化开发,就是把弹出框封装成一个组件,然后哪里使用哪里就调用,对,看来大家都是有思路的人,但是要怎样实现 ...
- 【转】手摸手,带你用vue撸后台 系列二(登录权限篇)
前言 拖更有点严重,过了半个月才写了第二篇教程.无奈自己是一个业务猿,每天被我司的产品虐的死去活来,之前又病了一下休息了几天,大家见谅. 进入正题,做后台项目区别于做其它的项目,权限验证与安全性是非常 ...
- 【转】手摸手,带你用vue撸后台 系列三(实战篇)
前言 在前面两篇文章中已经把基础工作环境构建完成,也已经把后台核心的登录和权限完成了,现在手摸手,一起进入实操. Element 去年十月份开始用vue做管理后台的时候毫不犹豫的就选择了Elemen, ...
- 原创 | 手摸手带您学会 Elasticsearch 单机、集群、插件安装(图文教程)
欢迎关注笔者的公众号: 小哈学Java, 每日推送 Java 领域干货文章,关注即免费无套路附送 100G 海量学习.面试资源哟!! 个人网站: https://www.exception.site/ ...
- 手摸手教你让Laravel开发Api更得心应手
https://www.guaosi.com/2019/02/26/laravel-api-initialization-preparation/ 1. 起因 随着前后端完全分离,PHP也基本告别了v ...
- 手摸手教你如何在 Python 编码中做到小细节大优化
手摸手教你如何在 Python 编码中做到小细节大优化 在列表里计数 """ 在列表里计数,使用 Python 原生函数计数要快很多,所以尽量使用原生函数来计算. &qu ...
随机推荐
- NSOperation 详解
原文地址:http://nshipster.com/nsoperation/ 大家都知道的秘密是一个应用程序,瞬间响应卸载计算在后台异步完成.因此,现代的Objective-C开发者有两种选择:大中央 ...
- uni-app获取dom元素到顶部的距离以及操作dom元素的一些样式
一. 1.首先有一个元素 <view class="activity" ref="btn"></view> 2.确认指针指向 this. ...
- 2018-7-29-C#-强转会不会抛出异常
title author date CreateTime categories C# 强转会不会抛出异常 lindexi 2018-7-29 14:24:1 +0800 2018-4-4 16:24: ...
- zoj 3859 DoIt is Being Flooded (MFSet && Flood Fill)
ZOJ :: Problems :: Show Problem 这题开始的时候想不到怎么调整每个grid的实际淹没时间,于是只好找了下watashi的题解,发现这个操作还是挺简单的. ZOJ3354 ...
- phpStudy本地环境测试,打开网页很慢的解决办法!
很多人应该都遇到了在使用phpStudy本地环境测试软件时候打开很慢的问题,甚至动辄达到了1000ms以上,开篇直接给出解决办法: 下面给大家介绍phpstudy访问速度慢的解决办法. 1.修改mys ...
- apply、call、bind方法调用
---恢复内容开始--- 首先这三个方法的作用都是用来改变this的值,而this的值一般有几种情况. 1.函数作为一个对象的一个方法来调用,此时this的值指向对象. var a={ v:0; f: ...
- [转载] linux下tar命令解压到指定的目录
参考 http://blog.sina.com.cn/s/blog_62449fcf0100nfar.html linux下tar命令解压到指定的目录 : #tar zxvf /bbs.tar.z ...
- python组件之wtforms
简介 帮助我们在HTML中快速生成form标签,同时还可以对用户提交的form请求的数据进行验证. 安装 pip3 install wtforms 使用 创建对象:构建form标签 class Log ...
- The 10th Shandong Provincial Collegiate Programming Contest H.Tokens on the Segments(贪心+优先级队列 or 贪心+暴力)
传送门 •题意 二维平面上有 n 条线段,每条线段坐标为 $(l_i,i),(r_i,i)$: 平面上的每个整点坐标上都可以放置一枚硬币,但是要求任意两枚硬币的横坐标不相同: 问最多有多少条线段可以放 ...
- gitLab操作规范和项目流程
刚做完一个项目并且艰难得上线,对整个项目流程和gitLab规范 有了一些心得,给新来的同学普及一下. 最先产品会写一篇需求文档,咱们要先看需求文档对项目有一个大致了解,然后产品喊后端.ui.前端 一 ...