前言

事情是这样的,作为一个意志力极低的人,最近一直在找寻提高意志力的方法。

然后决定试一试所谓的“建立奖励机制”,也就是说,完成一项意志力挑战后给自己一些奖励(具体操作方法不在这里进行赘述)。

那么,一款丝滑的“抽奖页面”也就理所当然加入了我的(瞎)待(折)办(腾)事项中。

整个过程还是比较简单的,涉及到的知识也相对基础,作为这个博客的第一篇技术文章,再加上作为一个技术小白,写的相对简单。希望能带个大家些许帮助,如果有建议批评也欢迎大家踊跃反馈。

涉及到的技术栈/框架

  • 前端开发基础知识(Html/Css/JavaScript)
  • Javascript ES6语法
  • Vue.js相关技术知识
  • JavaScript异步知识

基础代码

先上一段整体的基础代码

  1. <!DOCTYPE html>
  2. <html lang="zh">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Lottery</title>
  8. <style>
  9. #app {
  10. margin: auto;
  11. width: 200px;
  12. text-align: center;
  13. }
  14. </style>
  15. </head>
  16. <body>
  17. <div id="app">
  18. <p style="height:22px">{{item}}</p>
  19. <button @click="start">开始!</button>
  20. </div>
  21. <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  22. </body>
  23. <script>
  24. const app = new Vue({
  25. el: "#app",
  26. data: {
  27. list: ['1积分', '5积分', '10积分', '20积分', '谢谢惠顾', '再来一次'],
  28. item: "开始抽奖!"
  29. },
  30. methods: {
  31. start() {
  32. for (let index = 0; index < 50; index++) {
  33. setTimeout(() => {
  34. this.item = this.list[Math.round(Math.random() * (this.list.length - 1))]
  35. }, 100 + index * 100)
  36. }
  37. }
  38. }
  39. })
  40. </script>
  41. </html>

可以看到整体页面元素是再简单不过的,页面上除了 最外层的div元素 之外,就只剩一个用于启动抽奖的 按钮 和一个用于显示当前Item的 段落元素。通过外链的方式引用了 Vue框架

data中,list数组 作为奖池,用于放置可以被抽取到的item,item变量 则用来指明当前抽取到的item并与用于显示当前item的 段落元素 进行绑定 ,在 start方法 执行之前,item变量 默认值为“开始抽奖!”。

methods中只有一个 start方法 用于启动抽奖。通过 for循环 ,进行50次的抽取。setTimeOut 将抽取时间控制在100毫秒,也就是说每100毫秒进行一次抽取,从 list数组 中随机抽取值替换当前的 item变量


效果如下图️

需求

我们现有的基础功能毫无疑问是过于简陋的,僵硬的抽取过程,无严谨可言的抽取规则等等,让我们的抽奖系统现在看起来就像是并夕夕的 “赢取百万现金”轮盘一样透露和不可言说的廉价感,那么“如何改善”就显得尤为关键了。

  1. 优化抽取过程,使抽取过程流畅不那么僵硬
  2. 优化抽取规则,使抽取规则更为严谨
  3. 优化完善部分细节

完善过程

优化抽取过程

由于item抽取的间隔时间都为固定的100毫秒,看起来很呆板不丝滑,所以对抽取的间隔时间做出优化,让它看起来丝滑流畅一些。

  • start 方法的更新:
  1. async start() {
  2. for (let index = 0; index < 50; index++) {
  3. this.item = await new Promise(resolve => {
  4. setTimeout(() => {
  5. resolve(this.list[Math.round(Math.random() * (this.list.length - 1))])
  6. }, Math.round(this.getTime(index)))
  7. })
  8. }
  9. },

将异步函数 setTimeOut 进行 await 异步处理,让间隔时间可以叠加方便我们进行间隔时间的控制。由于使用了es6语法中的 await 关键字,所以此函数加上了 async 前缀。间隔时间使用新添加的函数 getTime 传参获取。

  • 新增 getTime 方法
  1. getTime(index) {
  2. // 初始/正常间隔时间
  3. let time = 80
  4. // 启动间隔时间处理
  5. if (index <= 10) {
  6. time = time + (11 - index) * 20
  7. }
  8. // 结束间隔时间的处理
  9. if (index >= 39) {
  10. time = time + (index - 39) * 20
  11. if (index === 49) time = 1000
  12. }
  13. return time
  14. }

通过参数 index 获取当时的循环次数,并计算出本次对应的 间隔时间 进行返回。(简单写的一个方法,且只针对于本项目,以后有空再进行封装完善。间隔时间的规律算法只经过了作者简单的计算,让它看起来比较符合作者对“顺滑”的定义,大家要是不喜欢也可以自己去尝试更改。毕竟现在是实验项目,能用就行)

优化抽取规则

由于抽取的规则并没有添加任何限制,导致项目抽取item的时候很可能抽取到的item与上一个相同,那就导致item在显示切换的时候出现问题,看起来好像并没有进行抽取。

  • start 方法的更新:
  1. async start() {
  2. for (let index = 0; index < 50; index++) {
  3. this.item = await new Promise(resolve => {
  4. setTimeout(() => {
  5. resolve(this.getItem())
  6. }, Math.round(this.getTime(index)))
  7. })
  8. }
  9. },

不再是简单的返回抽取结果,而是返回 getItem 方法计算出的item,对抽取的item结果添加限制。

  • 新增 getItem 方法
  1. getItem() {
  2. let newItem;
  3. do {
  4. newItem = this.list[Math.round(Math.random() * (this.list.length - 1))]
  5. } while (this.item === newItem);
  6. return newItem
  7. }

如果抽取到与上一个item相同的结果,那么就进行重复抽取,直到抽取到不同的结果为止。

优化细节

  1. data: {
  2. startButtonDisabled: false,
  3. finished: false,
  4. list: ['1积分', '5积分', '10积分', '20积分', '谢谢惠顾', '再来一次'],
  5. item: "开始抽奖!"
  6. },

data 中加入 startButtonDisabledfinished 用来分别记录按钮状态以及开奖的状态。

  1. handleStart(index) {
  2. if (index === 0) {
  3. this.finished = false
  4. this.startButtonDisabled = true
  5. }
  6. },
  7. handleEnd(index) {
  8. if (index === 49) {
  9. this.finished = true
  10. this.startButtonDisabled = false
  11. }
  12. }

添加函数 handleStarthandleEndstart 方法中循环体的首尾添加事件进行细节上的优化。在传入参数 index 为0(循环开始)时,利用方法 handleStart 将 开奖状态 改变为未开奖,按钮禁用,且在传入参数为49(循环结束)时,利用方法 handleEnd 再次改变其状态。

  1. async start() {
  2. for (let index = 0; index < 50; index++) {
  3. this.handleStart(index)
  4. this.item = await new Promise(resolve => {
  5. setTimeout(() => {
  6. resolve(this.getItem())
  7. }, Math.round(this.getTime(index)))
  8. })
  9. this.handleEnd(index)
  10. }
  11. },

start 方法的循环体首尾调用 handleStarthandleEnd 方法。

  1. <div id="app">
  2. <p :class="{active:finished}" style="height:22px">{{item}}</p>
  3. <button :disabled="startButtonDisabled" @click="start">开始!</button>
  4. </div>

将页面元素进行修改,使对应元素会随着 data 中数据状态的改变而产生变化。

  1. p.active {
  2. font-weight: bold;
  3. color: red
  4. }

最后为开奖状态为true的 active 类添加css样式,优化完成!

最终代码

  1. <!DOCTYPE html>
  2. <html lang="zh">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Lottery</title>
  8. <style>
  9. #app {
  10. margin: auto;
  11. width: 200px;
  12. text-align: center;
  13. }
  14. p.active {
  15. font-weight: bold;
  16. color: red
  17. }
  18. </style>
  19. </head>
  20. <body>
  21. <div id="app">
  22. <p :class="{active:finished}" style="height:22px">{{item}}</p>
  23. <button :disabled="startButtonDisabled" @click="start">开始!</button>
  24. </div>
  25. <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  26. </body>
  27. <script>
  28. const app = new Vue({
  29. el: "#app",
  30. data: {
  31. startButtonDisabled: false,
  32. finished: false,
  33. list: ['1积分', '5积分', '10积分', '20积分', '谢谢惠顾', '再来一次'],
  34. item: "开始抽奖!"
  35. },
  36. methods: {
  37. async start() {
  38. for (let index = 0; index < 50; index++) {
  39. this.handleStart(index)
  40. this.item = await new Promise(resolve => {
  41. setTimeout(() => {
  42. resolve(this.getItem())
  43. }, Math.round(this.getTime(index)))
  44. })
  45. this.handleEnd(index)
  46. }
  47. },
  48. getTime(index) {
  49. // 初始/正常间隔时间
  50. let time = 80
  51. // 启动间隔时间处理
  52. if (index <= 10) {
  53. time = time + (11 - index) * 20
  54. }
  55. // 结束间隔时间的处理
  56. if (index >= 39) {
  57. time = time + (index - 39) * 20
  58. if (index === 49) time = 1000
  59. }
  60. return time
  61. },
  62. getItem() {
  63. let newItem;
  64. do {
  65. newItem = this.list[Math.round(Math.random() * (this.list.length - 1))]
  66. } while (this.item === newItem);
  67. return newItem
  68. },
  69. handleStart(index) {
  70. if (index === 0) {
  71. this.finished = false
  72. this.startButtonDisabled = true
  73. }
  74. },
  75. handleEnd(index) {
  76. if (index === 49) {
  77. this.finished = true
  78. this.startButtonDisabled = false
  79. }
  80. }
  81. }
  82. })
  83. </script>
  84. </html>

效果如下️

结语

一个简单到不简单的前端例子而已,没有进行完善的封装,就这样发布了。希望嫩个够对大家有所帮助。以后我会尽量经常发布一些有营养的技术案例等等同时也会记录我在学习工作过程中遇到的有趣的知(坑)识。

感谢阅读,祝你生活愉快。

【JavasScript】折腾一个基础到不能再基础的顺滑抽奖页面的更多相关文章

  1. 记一个社交APP的开发过程——基础架构选型(转自一位大哥)

    记一个社交APP的开发过程——基础架构选型 目录[-] 基本产品形态 技术选型 最近两周在忙于开发一个社交App,因为之前做过一点儿社交方面的东西,就被拉去做API后端了,一个人头一次完整的去搭这么一 ...

  2. 【转】手摸手,带你用vue撸后台 系列四(vueAdmin 一个极简的后台基础模板)

    前言 做这个 vueAdmin-template 的主要原因是: vue-element-admin 这个项目的初衷是一个vue的管理后台集成方案,把平时用到的一些组件或者经验分享给大家,同时它也在不 ...

  3. 「六」创建一个带 weblogic 服务的基础镜像

    Weblogic Weblogic 简单介绍以及其在 Docker 环境下的特殊应用 WebLogic是美国Oracle公司出品的一个application server确切的说是一个基于JAVAEE ...

  4. 转:ORACLEERP开发基础之EBS开发基础

    转自:http://blog.itpub.net/8781091/viewspace-1012244/ [内容导航] 第1页:开发工具安装 第2页:增加数据块 第3页:注册表单FORM 第4页:注册请 ...

  5. .NET基础拾遗(1)类型语法基础和内存管理基础

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开发基 ...

  6. 基础拾掇之——http基础

    基础拾掇之——http基础 http协议介绍 http:Hyper Text Transfer Protocol 超文本传输协议,是互联网应用最为广泛的一种网络协议,主要用于Web服务.通过计算机处理 ...

  7. 20165206学习基础和C语言基础调查

    - 技能 我的一项可以拿的出手的技能是萨克斯.但不敢说有多厉害,更不敢说比大多数人更好,只能说是还可以.我学萨克斯有5年左右的时间吧,这5年里印象最深刻的还是前两年.前两年主要是基础训练.我从最基础的 ...

  8. 20165230 学习基础和C语言基础调查

    20165230 学习基础和C语言基础调查 技能学习经验 我擅长弹钢琴.小时候我曾上过很多兴趣班,比如钢琴.跳舞.书法.绘画等等,唯一坚持至今的只有钢琴.仔细一算学习钢琴至今已有12年,不能说已经精通 ...

  9. 20165237 学习基础和C语言基础调查

    学习基础和C语言基础调查 一.技能学习与特长 你有什么技能比大多人(超过90%以上)更好? 我的爱好和技能说实话挺广泛的.如果要挑出来一个很擅长的话,我觉得应该是钢琴. 针对这个技能的获取你有什么成功 ...

随机推荐

  1. python + pytest基本使用方法(运行测试&测试报告)

    import pytest# 1.运行名称中包含某字符串的测试用例#名称中含add 的测试用例# 执行: pytest -k add test_assert.py# 2.减少测试的运行冗长# 执行: ...

  2. 【Linux服务器双IP配置】如何实现不同IP的双网卡同时上网?

    一.环境和知识预备 我遇到问题的生产机器是CentOS release 6.8系统,不过这并不影响问题的解决,本质上都是一样的. 网关:一个网络连接到另一个网络的关口,也就是实现网络互连,俗称网络连接 ...

  3. 第四篇 -- Go语言string转其他类型

    1. string转int // 法1:string转int num_str := "1234567" /* ParseInt():查看文档https://studygolang. ...

  4. Java基础——ArrayList方法全解(字典版)

    引言 在使用集合 ArrayList 的时候,经常使用add.remove等,其他的没用过,甚至没听说过的还有很多.现在在这个教程中,简单的了解一下,不要求全都记下.相当于在你脑袋里建一个索引,就是有 ...

  5. jvm源码解读--10 enum WKID 枚举

    源码中对于枚举类型WKID的使用 static bool initialize_wk_klass(WKID id, int init_opt, TRAPS); static void initiali ...

  6. linux下利用JMX监控Tomcat

    利用JMX监控Tomcat,就是相当于部署在tomcat上的应用作为服务端,也就是被管理资源的对象.然后通过程序或者jconsole远程连接到该应用上来.远程连接需要服务器端提供ip和port.如果需 ...

  7. Django debug page XSS漏洞(CVE-2017-12794)

    影响版本:1.11.5之前的版本 访问http://your-ip:8000/create_user/?username=<script>alert(1)</script>创建 ...

  8. php 正则判断是否是手机号码

    $phonenumber = '13712345678'; if(preg_match("/^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|17[0-9]|1 ...

  9. Hadoop 3.1.1 - Yarn 服务 - 总览

    YARN 服务 总览 Yarn 服务框架为在 Yarn 原生环境里长时间运行的服务,提供了一流的支持和接口.简言之,它扮演了容器编排系统的角色,统一管理 Yarn 上运行的容器化服务.它同时支持 Do ...

  10. Thunder DLL Hijacking

    简记 原理基础啥的俺也不写了 1.寻找DLL 生成恶意dll文件 拿calc测试 2.放入 3.打开