【JS案例】JS实现积分抽奖(内附源码)

JS案例·实现积分抽奖
🌟效果展示
🌟HTML结构
🌟CSS样式
🌟实现思路
🌟具体实现
1.定义抽奖次数渲染
2.点击抽奖按钮,实现滚动抽奖效果
3.弹窗处理
🌟完整代码
🌟写在最后
🌟效果展示

视频转gif还是有点卡顿掉帧,实际效果非常流畅噢,文末有源码,可以带走玩玩!
🌟HTML结构
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>随机抽奖</title><link rel="stylesheet" href="./css/index.css">
</head><body><div class="main"><div class="content-container"><div class="prize-list"><img src="./img/prize_1.png" alt=""><span>IphoneX</span></div><div class="prize-list"><img src="./img/prize_2.png" alt=""><span>现金50元</span></div><div class="prize-list"><img src="./img/prize_3.png" alt=""><span>HUAWEI</span></div><div class="prize-list"><img src="./img/prize_4.png" alt=""><span>现金10元</span></div><div class="prize-list"><img src="./img/prize_5.png" alt=""><span>谢谢参与</span></div><div class="prize-list"><img src="./img/prize_6.png" alt=""><span>手机优惠券</span></div><div class="prize-list"><img src="./img/prize_7.png" alt=""><span>电脑优惠券</span></div><div class="prize-list"><img src="./img/prize_8.png" alt=""><span>U盘</span></div><!-- 中心内容部分 --><div class="handler-container"><div class="inner-container"><img class="handler-left" src="./img/center_1.png" alt=""><div class="handler-container-middle">还可以抽奖 <span class="prize-number">0</span> 次</div><div class="handler-container-btn"></div></div></div></div><div class="dialog-container"><div class="dialog-main"><div class="head"><span class="title">温馨提示</span><span class="close">×</span></div><div class="content">每次抽奖将消耗 8000 积分</div><div class="dialog-main-footer"><div class="button">再来一次</div></div></div></div></div><script src="./js/index.js"></script>
</body></html>
🌟CSS样式
* {margin: 0;padding: 0;
}.main {height: 546px;background-image: url('../img/banner-bg.jpg');position: relative;
}.content-container {position: absolute;width: 874px;height: 458px;background-image: url('../img/bg.png');left: 50%;top: 50%;transform: translate(-50%, -50%);
}.prize-list {width: 270px;height: 100px;position: absolute;width: 270px;height: 100px;padding: 5px;box-sizing: border-box;text-align: center;background: #622230;border: 1px solid #722536;border-radius: 5px;
}.prize-list>img {max-height: 75px;position: absolute;left: 30px;top: 15px;
}.prize-list>span {font-size: 19px;color: #ffb100;font-weight: bold;position: absolute;left: 102px;top: 36px;width: 164px;
}.prize-list:nth-child(1) {top: 22px;left: 26px;
}.prize-list:nth-child(2) {top: 22px;left: 302px;
}.prize-list:nth-child(3) {top: 22px;right: 26px;
}.prize-list:nth-child(4) {top: 129px;right: 26px;width: 100px;height: 200px;
}.prize-list:nth-child(4)>img,
.prize-list:nth-child(8)>img {left: 50%;transform: translateX(-50%);
}.prize-list:nth-child(4)>span,
.prize-list:nth-child(8)>span {left: 50%;transform: translateX(-50%);top: auto;bottom: 36px;
}.prize-list:nth-child(5) {bottom: 22px;right: 26px;
}.prize-list:nth-child(5)>img {top: 20px;
}.prize-list:nth-child(6)>img,
.prize-list:nth-child(7)>img {top: 25px;
}.prize-list:nth-child(6) {bottom: 22px;left: 302px;
}.prize-list:nth-child(7) {bottom: 22px;left: 26px;
}.prize-list:nth-child(8) {top: 129px;left: 26px;width: 100px;height: 200px;
}.handler-container {width: 614px;height: 198px;background-image: url('../img/middle-bg.png');position: absolute;left: 130px;top: 130px;display: table;
}.inner-container {display: table-cell;vertical-align: middle;padding: 0 20px;
}.handler-left {float: left;vertical-align: middle;
}.handler-container-middle {float: left;color: #ffd200;font-size: 30px;font-weight: bold;margin: 17px 0 0 18px;
}.handler-container-btn {width: 210px;height: 102px;background-image: url('../img/btn.png');float: right;cursor: pointer;
}.active {background-color: #ffd100;
}.active>span {color: #470c1b;
}/* 对话框样式 */.dialog-container {position: fixed;width: 100%;height: 100%;left: 0;top: 0;background-color: rgba(0, 0, 0, .5);display: none;
}.dialog-main {width: 400px;background-color: #fff;position: absolute;left: 50%;top: 30%;transform: translate(-50%, -50%);box-sizing: border-box;
}.dialog-main>.head {height: 50px;line-height: 50px;background-color: #e99c3d;border-bottom: 1px solid #ddd;box-sizing: border-box;padding: 0 20px;
}.dialog-main>.head>.title {float: left;color: #fff;font-size: 18px;
}.dialog-main>.head>.close {float: right;color: #fff;font-size: 42px;cursor: pointer;
}.dialog-main-footer {text-align: right;margin: 20px;
}.dialog-main>.content {text-align: center;margin: 20px;color: #622230;font-weight: bold;font-size: 20px;
}.dialog-main-footer>.button {background-color: #fca825;height: 28px;cursor: pointer;display: inline-block;line-height: 28px;color: #fff;padding: 0 10px;border-radius: 3px;
}
🌟实现思路
在敲完上面HTML文件和CSS文件后可以看到下图效果(图片素材及完整代码文末可下载):

接下来我们需要实现的就是以下步骤:
1: 定义抽奖次数渲染
1-1 获取DOM元素
1-2 定义剩余的抽奖次数
2: 点击抽奖按钮,实现滚动抽奖效果
2-1 获取点击按钮 ,绑定点击事件
2-2 为每一个list选项添加类名,实现高亮状态
2-3 定义当前高亮的列表项索引值
2-4 使用定时器实现滚动效果
2-5 使用随机数定义停止条件
3: 弹窗处理
3-1 打开弹窗.显示中奖信息(处理未中奖时的弹窗提示内容)
3-2 打开弹窗的同时,减少剩余的抽奖次数
3-3 关闭按钮的事件绑定
3-4 再来一次按钮事件绑定
那么就一步步开始实现吧!
🌟具体实现
1.定义抽奖次数渲染
获取DOM元素并在入口函数中赋值,这里默认赋值5次。
(function () {
let number = 5
let prizeNumber = document.querySelector('.prize-number')
let init = function () {prizeNumber.innerHTML = number}
init()
})()
2.点击抽奖按钮,实现滚动抽奖效果
获取点击按钮 ,绑定点击事件
let startBtn = document.querySelector('.handler-container-btn')
startBtn.addEventListener('click', onStartBtnClick)
let onStartBtnClick = function () {
}
接下来要给每一个list选项添加类名,实现高亮状态,那用什么方式来添加类名呢,可以看下图,目前这种方法也是觉大部分浏览器兼容,很好用:
document.querySelectorAll('.prize-list')[0].classList.add('active')
当点击开始抽奖按钮时,将执行一个定时器,这时高亮也将向前跳一步,其实就是给索引0加高亮-》清除所有高亮-》给索引1加高亮-》清除所有高亮 -》...如此就实现了跳向下一个的效果。
let prizeList = document.querySelectorAll('.prize-list')
let index = -1
let timer = null
let onStartBtnClick = function () {if (timer) returnindex = -1if (number === 0) returnrunGame()
}let runGame = function () {// 生成随机数控制定时器let random = Math.floor(Math.random() * 6000 + 3000)timer = setInterval(function () {random -= 200if (random < 200) {clearInterval(timer)timer = nullreturn}currentIndex = ++index % prizeList.lengthprizeList.forEach(function (node) {node.classList.remove('active')})prizeList[currentIndex].classList.add('active')}, 50)
}
3.弹窗处理
抽奖结束处理弹窗效果
let openDialog = function () {prizeNumber.innerHTML = --numberif (number === 0) {document.querySelector('.dialog-main-footer .button').innerHTML = '确定'}dialogContainer.style.display = 'block'if (currentIndex === 4) {prizeContent.innerHTML = '很遗憾您没有中奖'} else {prizeContent.innerHTML = '恭喜您获得' + document.querySelector('.active span').innerHTML}
}

接下来就是一些细节处理与函数封装,就不细讲了,源码在下面。
🌟完整代码
HTML和CSS文件就是上面代码无变化,下面是index.js文件:
/*
1: 定义抽奖次数渲染1-1 获取DOM元素1-2 定义剩余的抽奖次数
2: 点击抽奖按钮,实现滚动抽奖效果(复杂度高)2-1 获取点击按钮 ,绑定点击事件2-2 为每一个list选项添加类名,实现高亮状态2-3 定义当前高亮的列表项索引值2-4 使用定时器实现滚动效果2-5 使用随机数定义停止条件
3: 弹窗处理 3-1 打开弹窗.显示中奖信息(处理未中奖时的弹窗提示内容)3-2 打开弹窗的同时,减少剩余的抽奖次数3-3 关闭按钮的事件绑定3-4 再来一次按钮事件绑定 */(function () {let startBtn = document.querySelector('.handler-container-btn')let prizeList = document.querySelectorAll('.prize-list')let dialogContainer = document.querySelector('.dialog-container');let prizeContent = document.querySelector('.dialog-container .content')let index = -1let timer = nulllet number = 5let currentIndex = nulllet closeBtn = document.querySelector('.close')let confirmBtn = document.querySelector('.dialog-main-footer .button')let prizeNumber = document.querySelector('.prize-number')let init = function () {prizeNumber.innerHTML = numberinitEvent()}let initEvent = function () {startBtn.addEventListener('click', onStartBtnClick)closeBtn.addEventListener('click', onCloseBtnClick)confirmBtn.addEventListener('click', onConfirmBtnClick)}let onStartBtnClick = function () {if (timer) returnindex = -1if (number === 0) returnrunGame()}/* 关闭弹窗 */let onCloseBtnClick = function () {dialogContainer.style.display = 'none'}let onConfirmBtnClick = function () {index = -1dialogContainer.style.display = 'none'if (number === 0 || timer) returnrunGame()}let runGame = function () {let random = Math.floor(Math.random() * 6000 + 3000)timer = setInterval(function () {random -= 200if (random < 200) {clearInterval(timer)timer = nullopenDialog()return}currentIndex = ++index % prizeList.lengthprizeList.forEach(function (node) {node.classList.remove('active')})prizeList[currentIndex].classList.add('active')}, 50)}let openDialog = function () {prizeNumber.innerHTML = --numberif (number === 0) {document.querySelector('.dialog-main-footer .button').innerHTML = '确定'}dialogContainer.style.display = 'block'if (currentIndex === 4) {prizeContent.innerHTML = '很遗憾您没有中奖'} else {prizeContent.innerHTML = '恭喜您获得' + document.querySelector('.active span').innerHTML}}init()
})()
完整源码及图片素材免费下载地址:点击免费下载
🌟写在最后
本专栏将持续更新原生JS案例,提供一些工作中也能用上的一些小案例,详细讲解分析,提升JS开发水平与开发思路的积累,如果文中出现有瑕疵的地方各位通过评论或者私信联系我,我们一起进步,有兴趣的伙伴可以订阅一下:点击关注JS经典案例专栏

相关文章:
【JS案例】JS实现积分抽奖(内附源码)
JS案例实现积分抽奖 🌟效果展示 🌟HTML结构 🌟CSS样式 🌟实现思路 🌟具体实现 1.定义抽奖次数渲染 2.点击抽奖按钮,实现滚动抽奖效果 3.弹窗处理 🌟完整代码 🌟写在最后 dz…...
angular抛出 ExpressionChangedAfterItHasBeenCheckedError错误分析
当变更检测完成后又更改了表达式值时,Angular 就会抛出 ExpressionChangedAfterItHasBeenCheckedError 错误。Angular 只会在开发模式下抛出此错误。 在开发模式下,Angular 在每次变更检测运行后都会执行一次附加检查,以确保绑定没有更改。这…...
动态链接库的__declspec(dllexport)关键字的概念
在 Windows 操作系统下,创建一个动态链接库(DLL)项目时,您需要通过 __declspec(dllexport) 关键字来显式地标记希望在 DLL 中 公开 的函数、类、变量等符号。这是因为在默认情况下,编译器会将函数和符号视为 私有&…...
群晖NAS:DS Video、Jellyfin等视频电影电视剧海报、背景墙搜刮器
群晖NAS:DS Video、Jellyfin等视频电影电视剧海报、背景墙搜刮器 本文只使用豆瓣插件方式,系统默认的 The Movie Database 好注册,但是授权码输入后域名不通过,很麻烦。 1、插件地址: https://www.aliyundrive.com/s…...
WEBGL(3):鼠标动态绘制点
1 实现思路 绘制单个点鼠标事件监听点击事件将点推送到数组中绘制数组中所有点 2 实现代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge&…...
Sass基础
Sass基础 简介 Sass是一种stylesheet语言,可以被编译成CSS。Sass允许你使用诸如variabels,nested rules,mixins,functions等等语法,这些都将在本篇的接下来进行讲解。 因为之前一直学的后端,前端只是因为…...
Java中的消息队列有哪些?
在Java中,有几种常见的消息队列实现,包括: Apache Kafka:一个分布式流处理平台,具有高吞吐量、可持久化、可扩展等特点。 RabbitMQ:一个开源的消息代理,实现了AMQP(高级消息队列协议…...
多维时序 | Matlab实现GRU-Adaboost和GRU多变量时间序列预测对比
多维时序 | Matlab实现GRU-Adaboost和GRU多变量时间序列预测对比 目录 多维时序 | Matlab实现GRU-Adaboost和GRU多变量时间序列预测对比预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 多维时序 | Matlab实现GRU-Adaboost和GRU多变量时间序列预测对比 模型描述 M…...
测试用例编写规范参考
章节目录: 一、规范目的二、模块划分三、颗粒度规范四、编写规范五、具体分项5.1 用例标题5.2 前置条件5.3 操作步骤5.4 预期结果 六、用例维护七、结束语 一、规范目的 规范合理,可执行性。一定要保证高可读性。 二、模块划分 同级别、同等级功能点。…...
unity3d:功能验证,收集开源项目的工程合集
unity3d功能验证,和收集开源项目的工程合集 目录持续更新地址 【腾讯文档】UnityForTest目录 https://docs.qq.com/doc/DWm9HSkVhTGdyUUVo 源码 https://github.com/luoyikun/UnityForTest 动画 创建骨骼动画 BoneAnimation场景 代码创建Mesh,骨骼…...
plotly_beforehover 用法:
在Plotly.js中,plotly_beforehover是在鼠标悬停在数据点上之前触发的回调事件。它的主要作用是在鼠标悬停事件发生前做一些准备工作。 plotly_beforehover事件是与图表对象绑定的,可以通过调用on方法来绑定事件处理程序。下面是一个示例代码:…...
利用 AI 赋能云安全,亚马逊云科技的安全技术创新服务不断赋能开发者
文章分享自亚马逊云科技 Community Builder:李少奕 2023年6月14日,一年一度的亚马逊云科技 re:Inforce 全球大会在美国安纳海姆落下了帷幕。re:Inforce 是亚马逊云科技全球最大的盛会之一,汇集了来自全球各地的安全专家,共同学习、…...
18. 填坑Ⅰ
Description 又是北湖深坑,惊不惊喜,意不意外?! 觉得用水填湖太没意思了,用石头填坑多有意思。 假设北湖的地面还是一维的,每一块宽度都为1,高度是非负整数,用一个数组来表示。 现提…...
CSS 实现平面圆点绕椭圆动画
前言 👏CSS实现平面圆点绕椭圆动画,速速来Get吧~ 🥇文末分享源代码。记得点赞关注收藏! 1.实现效果 2.实现原理 transform-style:CSS 属性 transform-style 设置元素的子元素是位于 3D 空间中还是平面中。如果选择平面…...
docker login : x509: certificate signed by unknown authority
一. 背景 docker login 登录harbor镜像仓库报错. [rootmaster01 sloth]# docker login docker.harbor.master01.com Username: bigdata Password: Error response from daemon: Get https://docker.harbor.master01.com/v2/: x509: certificate signed by unknown authority …...
金蝶云星空二开,插件查看工具
可查询单据上挂载的系统原有插件、二开插件及插件类型 1.支持模糊查询单据列表 2.支持项目与账套二开插件对比 3.支持金蝶不同账套之间对比差异 操作步骤: 1.登陆界面,选择金蝶云管理中心账套登录获取账套列表; 2.单一标识查询:…...
error: ‘std::_hypot‘ has not been declared using std::hypot;
Cmake 使用qt的编译器 编译opencv时 执行mingw32-make时出现了错误 本质原因就是 _hypot 没有声明。所以找到对应的文件声明一下 就行了。 E:\*****\Qt5.14.1\Tools\mingw730_64\lib\gcc\x86_64-w64-mingw32\7.3.0\include\c 下面的math.h 文件。 可以看到这个文件有一个…...
介绍 Apache Spark 的基本概念和在大数据分析中的应用。
Apache Spark 是一个快速的开源大数据处理引擎,可以用于大数据处理、机器学习、图形计算等领域。它可以在多种计算环境中运行,包括独立模式、YARN、Mesos、Kubernetes等云计算平台。 Spark基于RDD(Resilient Distributed Datasets࿰…...
Java设计模式:四、行为型模式-09:模板模式
文章目录 一、定义:模板模式二、模拟场景:模板模式三、改善代码:模板模式3.0 引入依赖3.1 工程结构3.2 模板模式结构图3.3 爬取商品生成海报实现3.3.1 HTTP获取连接类3.3.2 定义执行顺序的抽象类3.3.3 当当爬取抽象实现类3.3.4 京东爬取抽象实…...
【前端】Vue2 脚手架模块化开发 -快速入门
🎄欢迎来到边境矢梦的csdn博文🎄 🎄本文主要梳理Vue2 脚手架模块化开发 🎄 🌈我是边境矢梦,一个正在为秋招和算法竞赛做准备的学生🌈 🎆喜欢的朋友可以关注一下🫰&#x…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
Android第十三次面试总结(四大 组件基础)
Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成,用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机: onCreate() 调用时机:Activity 首次创建时调用。…...
C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
