单计时器的简单抽奖与相关扩展
首先来看一个简单的列子 是一个固定选项的抽奖页面 最终实现的效果是点击开始按钮之后会随机让一个单元格的背景色变成黄色 是一个很简单的抽奖 css样式部分小伙伴门可以自行调整简单抽奖!DOCTYPEhtmlhtmllangenheadmetacharsetUTF-8metanameviewportcontentwidthdevice-width, initial-scale1.0titleDocument/title/headbodydividappbuttonclassbtnstart/buttondivclasscontainerdivclassbasis-box1/divdivclassbasis-box2/divdivclassbasis-box3/divdivclassbasis-box4/divdivclassbasis-box5/divdivclassbasis-box6/div/div/div/bodyscriptconstbtndocument.querySelector(.btn);//获取按钮//获取所有格子constcellListdocument.getElementsByClassName(basis-box);letindex0;//记录当前显示的cell索引// 添加点击事件btn.addEventListener(click,function(){cellList[index].classList.remove(highlight)indexMath.floor(Math.random()*cellList.length);cellList[index].classList.add(highlight)});/scriptstylebody{width:100vw;/* 占满窗口 */padding:0;}#app{width:100%;display:flex;flex-direction:column;align-items:center;}/* 按钮的样式 */.btn{width:60px;height:40px;}.container{display:flex;flex-direction:row;/* 横向排列每一个cell */font-size:28px;margin-top:10px;margin-bottom:10px;}.basis-box{display:flex;justify-content:center;/* 垂直居中 */align-items:center;/* 水平居中 */width:100px;height:100px;margin-left:10px;border:2px solid black;/* 边框 */}/* 用来表示选项的类 */.highlight{background-color:yellow;}/style/html这样就实现了一个简单的抽奖 但是这样的没有灵魂好看的动画效果这里只展示js的具体逻辑效果 css 的可以自行定义具体实现想要实现动画效果也就是实现随着时间变化速度也跟随一起变化的效果自然需要计时器但是计时器多了会造成严重的卡顿故此可以使用一个计时器实现这个效果。实现思路如下增加速度变量让计时器按照一定的tick进行速度可以使用时间 也可以使用计数器本文使用计数器实现速度变化 类似于我的世界的tick设计像是这个样子 就可以实现一个简单的往复运动的抽奖但是有个问题 这个每次都会落到一个方块上btn.addEventListener(click,function(){updateCell();});constupdateCell(){letpreIndex0;lettickCount0;//记录已经更新的次数letcurInterval2;//当前间隔letpreUpdateTick0;//上次更新的tick数// 初始化第一个高亮cellList[index].classList.remove(highlight);consttimersetInterval((){tickCount;if(tickCount-preUpdateTickcurInterval){preUpdateTicktickCount;curIntervalcomputedInterval(tickCount);// 更新高亮显示cellList[index].classList.remove(highlight);// 使用数学公式实现往复高亮indexMath.abs((preIndex%(2*cellList.length-2))-(cellList.length-1));cellList[index].classList.add(highlight);}if(tickCountmaxTick){clearInterval(timer);console.log(动画结束);return;}},tick);}constcomputedInterval(tickCount){if(tickCountmaxTick/3){return2;}elseif(tickCount(maxTick/3)*2){return5;}elseif(tickCountmaxTick){return7;}}可以给这个抽奖添加一个随机的初始位置实现随机的效果并且可以优化一下现在的动画变动效果 现在的略显卡顿 tick也就是帧率 调小之后会变得更加流畅改动之后的间隔计算 增加阶段机制 让其更像是游戏里的抽奖 具体数值可以自己调整constcomputedInterval(tickCount){constprogresstickCount/maxTick;// 使用缓动函数实现更自然的减速效果if(progress0.15){// 一阶段:0-15%return1progress*20;// 1 - 4}elseif(progress0.35){// 二阶段:15%-35%constp(progress-0.15)/0.2;return4p*8;// 4 - 12}elseif(progress0.6){// 三阶段:中速 (35%-60%)constp(progress-0.35)/0.25;return12p*13;// 12 - 25}elseif(progress0.85){// 四阶段:慢速 (60%-85%)constp(progress-0.6)/0.25;return25p*20;// 25 - 45}else{// 五阶段:85%-100%constp(progress-0.85)/0.15;return45p*35;// 45 - 80}}新的更新函数 增加了一个随机初始位置 并且增加一个随机是否反向运动增加随机性 这样的抽奖看起来更加的灵动constupdateCell(){// 随机起始位置letpreIndexMath.floor(Math.random()*cellList.length);lettickCount0;//记录已经更新的次数letcurInterval1;//初始间隔letpreUpdateTick0;//上次更新的tick数// 随机决定是否反向运动letdirectionMath.random()0.5?1:-1;if(direction-1){preIndexcellList.length-1-preIndex;}// 初始化第一个高亮cellList[index].classList.remove(highlight);indexpreIndex;cellList[index].classList.add(highlight);consttimersetInterval((){// 同上}}扩展建议动态增加/删除格子可以在抽奖过程中或开始前动态调整格子数量让游戏更具灵活性!-- 添加控制按钮 --divclasscontrolsbuttonidaddCellBtn 添加格子/buttonbuttonidremoveCellBtn- 删除格子/button/div// 动态添加格子constaddCell(){constnewCelldocument.createElement(div);newCell.classNamebasis-box;newCell.textContentcellList.length1;container.appendChild(newCell);cellListdocument.getElementsByClassName(basis-box);};// 动态删除格子至少保留2个constremoveCell(){if(cellList.length2){container.removeChild(container.lastElementChild);cellListdocument.getElementsByClassName(basis-box);// 如果当前索引超出范围重置为0if(indexcellList.length){index0;}}};document.getElementById(addCellBtn).addEventListener(click,addCell);document.getElementById(removeCellBtn).addEventListener(click,removeCell);自定义格子内容允许用户为每个格子设置自定义文本或图片// 双击格子编辑内容cellList.forEach((cell,idx){cell.addEventListener(dblclick,(){constnewTextprompt(请输入第${idx1}个格子的内容:,cell.textContent);if(newText!nullnewText.trim()!){cell.textContentnewText;}});});多种动画模式提供不同的动画效果供用户选择constanimationModes{// 往复运动默认bounce:(counter,length){returnMath.abs((counter%(2*length-2))-(length-1));},// 单向循环loop:(counter,length){returncounter%length;},// 随机跳动random:(counter,length){returnMath.floor(Math.random()*length);},// 螺旋式减速spiral:(counter,length,maxTick){constprogresscounter/maxTick;constspeed1Math.pow(progress,3)*10;returnMath.floor(counter/speed)%length;}};// 使用示例constmodebounce;// 可切换indexanimationModes[mode](preIndex,cellList.length,maxTick);概率控制系统为不同格子设置不同的中奖概率// 定义每个格子的权重概率constweights[10,20,30,15,15,10];// 数值越大概率越高// 根据权重随机选择最终结果constweightedRandom(){consttotalWeightweights.reduce((sum,w)sumw,0);letrandomMath.random()*totalWeight;for(leti0;iweights.length;i){random-weights[i];if(random0){returni;}}returnweights.length-1;};// 在updateCell中使用constfinalIndexweightedRandom();// ... 计算总步数时以finalIndex为终点