【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…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...
基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)
引言 在嵌入式系统中,用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例,介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单,执行相应操作,并提供平滑的滚动动画效果。 本文设计了一个…...
数据库——redis
一、Redis 介绍 1. 概述 Redis(Remote Dictionary Server)是一个开源的、高性能的内存键值数据库系统,具有以下核心特点: 内存存储架构:数据主要存储在内存中,提供微秒级的读写响应 多数据结构支持&…...
