当前位置:首页 > 生活 >

抽抽乐怎么做好看又简单

来源:原点资讯(www.yd166.com)时间:2023-12-22 00:15:39作者:YD166手机阅读>>

那我们就来学点有意思的,用几十行代码来实现一个高性能的抽奖小游戏.也基于此,来巩固我们的javascript基础,以及前端一些基本算法的应用.

效果展示

抽抽乐怎么做好看又简单,(1)

你将收获
  • 防抖函数的应用
  • 用css实现九宫格布局
  • 生成n维环形坐标的算法
  • 如何实现环形随机轨道运动函数
  • 实现加速度动画
  • 性能分析与优化
设计思路

抽抽乐怎么做好看又简单,(2)

具体实现

由于目前已有很多方案可以实现九宫格抽奖动画,比如使用动态active实现边框动画,用随机算法和定时器设置在何处停止等等. 为了进一步提高性能,本文介绍的方法,将使用坐标法,将操作dom的成本降低,完全由js实现滑块的路径的计算,滑块元素采用绝对定位,让其脱离文档流,避免其他元素的重绘等等,最后点击按钮我们会使用防抖函数来避免频繁执行函数,造成不必要的性能损失.

1. 九宫格布局实现

为了让大家更加熟悉dom结构,这里我就不用js动态生成了.如下html结构:

<div class="wrap"> <div class="title">圣诞抽抽乐</div> <div class="box"> <div class="item">我爱你</div> <div class="item">你爱我</div> <div class="item">我不爱你</div> <div class="item">你爱我</div> <div class="item start">开始</div> <div class="item">你爱我</div> <div class="item">再见</div> <div class="item">谢谢惠顾</div> <div class="item">你爱我</div> <div class="spin"></div> </div> </div> 复制代码

九宫格布局我们使用flex来实现,核心代码如下:

.box { display: flex; flex-wrap: wrap; width: 300px; height: 300px; position: relative; .item { box-sizing: border-box; width: 100px; } // 滑块 .spin { box-sizing: border-box; position: absolute; left: 0; top: 0; display: inline-block; width: 100px; height: 100px; background-color: rgba(0,0,0,.2); } } 复制代码

由上可知容器box采用flex布局,要想让flex子元素换行,我们这里要设置flex-wrap: wrap;此时九宫格布局就实现了. 滑块采用绝对定位,至于具体如何去沿着环形轨道运动,请继续看下文介绍.

2.生成n维环形坐标的算法

抽抽乐怎么做好看又简单,(3)

由上图我们可以知道,一个九宫格的4条边,可以用以上8个坐标收尾连接起来,那么我们可以基于这个规律.来生成环形坐标集合.代码如下:

/** * 生成n维环形坐标 * @param {number} n 维度 * @param {number} cell 单位坐标长度 */ function generateCirclePath(n, cell) { let arr = [] for(let i=0; i< n; i ) { arr.push([i*cell, 0]) } for(let i=0; i< n-1; i ) { arr.push([(n-1)*cell, (i 1)*cell]) } for(let i=0; i< n-1; i ) { arr.push([(n-i-2)*cell, (n-1)*cell]) } for(let i=0; i< n-2; i ) { arr.push([0, (n-i-2)*cell]) } return arr } 复制代码

如果是单位坐标,那么cell为1,cell设计的目的就位为了和现实的元素相结合,我们可以手动设置单元格的宽度来实现不同大小的n维环形坐标集.

3.实现环形随机轨道运动函数

由抽奖动画分析可知,我们滑块运动的轨迹,其实就是环形坐标集合,所以我们只要让滑块的顶点(默认左上角)沿着环形坐标集合一步步变化就好了.

function run(el, path, n = 1, i = 0, len = path.length) { setTimeout(() => { if(n > 0) { if(len <= i) { i = n === 1 ? len : 0 n-- } el.css('transform', `translate(${path[i][0]}px, ${path[i][1]}px)`) run(el, path, n, i, len) } }, 300) } 复制代码

这样就能实现我们的滑块按照九宫格边框运动的动画了,当然以上函数只是基本的动画, 还没有实现在随机位置停止, 以及滑块的加速度运动,这块需要一定的技巧和js基础知识比如闭包.

3.1 加速度运动

加速度运动其实很简单,比如每转过一圈将setTimeout的延迟时间改变即可.代码如下:

function run(el, path, n = 1, speed = 60, i = 0, len = path.length) { setTimeout(() => { if(n > 0) { if(len <= i) { i = n === 1 ? len : 0 n-- speed = (300 - speed) / n } el.css('transform', `translate(${path[i][0]}px, ${path[i][1]}px)`) run(el, path, n, speed, i, len) } }, speed) } 复制代码3.2 随机停止实现

随机停止这块主要是用了Math.random这个API, 我们在最后一圈的时候, 根据随机返回的数值来决定何时停止,这里我们在函数内部实现随机数值,完整代码如下:

/** * 环形随机轨道运动函数 * @param {element} el 运动的dom元素 * @param {array} path 运动的环形坐标集合 * @param {number} speed 运动的初始速度 * @param {number} i 运动的初始位置 * @param {number} len 路径的长度 * @param {number} random 中奖坐标 */ function run(el, path, n = 1, speed = 60, i = 0, len = path.length, random = Math.floor(Math.random() * len)) { setTimeout(() => { if(n > 0) { // 如果n为1,则设置中奖数值 if(n === 1) { len = random } if(len <= i) { i = n === 1 ? len : 0 n-- speed = (300 - speed) / n } el.css('transform', `translate(${path[i][0]}px, ${path[i][1]}px)`) run(el, path, n, speed, i, len, random) } }, speed) } 复制代码4.实现点击开始的防抖函数以及应用

防抖函数实现:

// 防抖函数,避免频繁点击执行多次函数 function debounce(fn, interval = 300) { let timeout = null return function () { clearTimeout(timeout) timeout = setTimeout(() => { fn.apply(this, arguments) }, interval) } } 复制代码

那么我们点击时,代码应该长这样:

// 点击开始按钮,开始抽奖 $('.start').on('click',debounce(() => { run($('.spin'), generateCirclePath(3, 100), 3) })) 复制代码延伸

在文章发布之后,有热心的小伙伴们提出了几个建议,综合如下:

  • 抽奖动画结束后提供回调来通知页面以便处理其他逻辑
  • 处理多次点击时,虽然加了防抖,但是用户在动画没结束时点击了开始按钮,又会执行动画导致动画越来越快,发生混乱.

综合以上问题,我在之前基础上做了进一步扩展,来解决以上提到的问题.

  1. 添加动画结束时回调:

/** * 环形随机轨道运动函数 * @param {element} el 运动的dom元素 * @param {array} path 运动的环形坐标集合 * @param {func} cb 动画结束时回调 * @param {number} speed 运动的初始速度 * @param {number} i 运动的初始位置 * @param {number} len 路径的长度 * @param {number} random 中奖坐标 */ function run(el, path, n = 1, cb, speed = 60, i = 0, len = path.length, random = Math.floor(Math.random() * len)) { setTimeout(() => { if(n > 0) { // 如果n为1,则设置中奖数值 if(n === 1) { len = random } if(len <= i) { i = n === 1 ? len : 0 n-- speed = (300 - speed) / n } el.css('transform', `translate(${path[i][0]}px, ${path[i][1]}px)`) run(el, path, n, cb, speed, i, len, random) }else { cb && cb() } }, speed) } 复制代码

  1. 处理多次点击时,虽然加了防抖,但是用户在动画没结束时点击了开始按钮,又会执行动画导致动画越来越快,发生混乱.

// 1. 点击开始按钮,开始抽奖 $('.start').on('click',debounce(() => { // 点击开始后禁用点击 $('.start').css('pointer-events', 'none') run($('.spin'), generateCirclePath(3, 100), 3, () => { // 动画结束后开启按钮点击 $('.start').css('pointer-events', 'auto') alert('抽奖结束') }) })) 复制代码

谢谢各位认真的建议,继续优化吧.

总结

该实现方式的好处是支持n维环形坐标的抽奖,基于坐标法的应用还有很多,尤其是游戏和图形领域,在实现过程中一定要考虑性能和可扩展性,这样我们就可以在不同场景使用同一套方法论,岂不乐哉?本文完整源码我会放在github上,欢迎交流学习~

github地址:https://github.com/MrXujiang?tab=repositories

欢迎在公众号《趣谈前端》加入我们一起学习讨论,共同探索前端的边界。

栏目热文

盲袋抽抽乐(抽盲袋洞洞乐)

盲袋抽抽乐(抽盲袋洞洞乐)

转眼间,五一小长假就过去了!重回工作怀抱的大家,有没有燃起激情?刚好,乐高也上新了一大波新品,不如用它们来激励自己!小乐...

2023-12-22 00:05:45查看全文 >>

手工制作抽抽乐(制作好玩的手工抽抽乐)

手工制作抽抽乐(制作好玩的手工抽抽乐)

婴儿的很多早教游戏是跟手部精细动作有关的,孩子学的抽纸,用手抓握物品都是手部精细动作。依稀记得土豆当时6个月去做体检时,...

2023-12-22 00:14:07查看全文 >>

miss排位日记(miss排位日记开场动画)

miss排位日记(miss排位日记开场动画)

fearless,s十四,四费到底谁来c?这期视频miss告诉你ez,Miss预测是一个强力热门的主c。ez技能机制和数...

2023-12-21 23:46:54查看全文 >>

电竞女王miss个人资料(电竞一姐miss是什么)

电竞女王miss个人资料(电竞一姐miss是什么)

说起韩懿莹,可能好多人不认识,但是说到Miss,电竞圈的人应该都认识!Miss曾经是一名玩家,她玩游戏的水平可不一般,而...

2023-12-22 00:23:23查看全文 >>

miss英语是什么意思(miss在英语中代表什么)

miss英语是什么意思(miss在英语中代表什么)

1.适用性别不同:Mr. 是对男性的称呼,Mrs,Ms,Miss都是对女性的称呼Mr 意为“先生” ,一般用于男子姓、名...

2023-12-21 23:48:40查看全文 >>

无敌抽抽乐详细教程(可以扭来扭去的抽抽乐教程)

无敌抽抽乐详细教程(可以扭来扭去的抽抽乐教程)

本内容来源于@什么值得买APP,观点仅代表作者本人 |作者:刀哥没有钱创作立场声明:纯推荐,可以放心食用,大佬们求轻喷作...

2023-12-22 00:14:11查看全文 >>

儿童自制手工洞洞乐步骤(儿童自制手工多层洞洞乐教程)

儿童自制手工洞洞乐步骤(儿童自制手工多层洞洞乐教程)

亲子游戏:小积木。准备了两个道具:小积木、一堆奥特曼卡牌。这些奥特曼卡牌能扔进去多少?就来猜多少,能猜到多少?道具放中间...

2023-12-21 23:59:15查看全文 >>

自制洞洞乐教程(自制洞洞乐教程 超级简单)

自制洞洞乐教程(自制洞洞乐教程 超级简单)

嘀嘀嘀,我奥特曼出来巡逻了。前面是什么?看上去还挺漂亮的。小萝莉,这是什么?奥特曼,这是我新买的洞洞乐游戏,要不要和我一...

2023-12-21 23:53:55查看全文 >>

怎么修改已完成的滴滴订单(滴滴平台怎么修改订单)

怎么修改已完成的滴滴订单(滴滴平台怎么修改订单)

各位车主大大你们一定遇到过下面这种情况!目的地不一致师傅,您先开到这个地方,我在这下。然后把我朋友送到这个地方。你朋友下...

2023-12-21 23:51:22查看全文 >>

滴滴车主怎么设置订单接或不接(滴滴怎么设置不接场站订单)

滴滴车主怎么设置订单接或不接(滴滴怎么设置不接场站订单)

九月一号了,新的开始,然而很多人可能不愿意接拼车单。目前上海的拼车单有两种,一种是优先拼车,价格较高,大多数人不会选择。...

2023-12-22 00:14:32查看全文 >>

文档排行