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

news2025/1/16 8:13:22

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">&times;</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) return
  index = -1
  if (number === 0) return
  runGame()
}

let runGame = function () {
   // 生成随机数控制定时器
  let random = Math.floor(Math.random() * 6000 + 3000)
  timer = setInterval(function () {
    random -= 200
    if (random < 200) {
      clearInterval(timer)
      timer = null
      return
    }
    currentIndex = ++index % prizeList.length
    prizeList.forEach(function (node) {
      node.classList.remove('active')
    })
    prizeList[currentIndex].classList.add('active')
  }, 50)
}

 3.弹窗处理

抽奖结束处理弹窗效果


let openDialog = function () {
  prizeNumber.innerHTML = --number
  if (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 = -1
  let timer = null
  let number = 5
  let currentIndex = null
  let closeBtn = document.querySelector('.close')
  let confirmBtn = document.querySelector('.dialog-main-footer .button')
  let prizeNumber = document.querySelector('.prize-number')

  let init = function () {
    prizeNumber.innerHTML = number
    initEvent()
  }

  let initEvent = function () {
    startBtn.addEventListener('click', onStartBtnClick)
    closeBtn.addEventListener('click', onCloseBtnClick)
    confirmBtn.addEventListener('click', onConfirmBtnClick)
  }

  let onStartBtnClick = function () {
    if (timer) return
    index = -1
    if (number === 0) return
    runGame()
  }

  /* 关闭弹窗 */
  let onCloseBtnClick = function () {
    dialogContainer.style.display = 'none'
  }

  let onConfirmBtnClick = function () {
    index = -1
    dialogContainer.style.display = 'none'
    if (number === 0 || timer) return
    runGame()
  }

  let runGame = function () {
    let random = Math.floor(Math.random() * 6000 + 3000)
    timer = setInterval(function () {
      random -= 200
      if (random < 200) {
        clearInterval(timer)
        timer = null
        openDialog()
        return
      }
      currentIndex = ++index % prizeList.length
      prizeList.forEach(function (node) {
        node.classList.remove('active')
      })
      prizeList[currentIndex].classList.add('active')
    }, 50)
  }

  let openDialog = function () {
    prizeNumber.innerHTML = --number
    if (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经典案例专栏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/960649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿里面试经验分享:从被回绝到Offer,详解应聘阿里技术岗位注意事项

本文是《谈谈应聘阿里全流程》的姊妹篇&#xff0c;《谈谈应聘阿里全流程》发布后&#xff0c;收到了很多读者的积极反馈&#xff0c;但其中也反映出读者普遍的困惑&#xff1a;清楚了应聘流程&#xff0c;该如何有针对性地做应聘准备呢&#xff1f;这个问题从正面并不好回答&a…

windows自带远程桌面连接的正确使用姿势

摘要 目前远程办公场景日趋广泛&#xff0c;对远程控制的需求也更加多样化&#xff0c;windows系统自带了远程桌面控制&#xff0c;在局域网内可以实现流程的远程桌面访问及控制。互联网使用远程桌面则通常需要使用arp等内网穿透软件&#xff0c;市场上teamviewer、Todesk、向…

浅探Android 逆向前景趋势~

前段时间&#xff0c;我和朋友偶然间谈起安卓逆向&#xff0c;他问我安卓逆向具体是什么&#xff0c;能给我们带来什么实质性的东西&#xff0c;我也和朋友大概的说了一下&#xff0c;今天在这里拿出来和大家讨论讨论&#xff0c;也希望帮助大家来了解安卓逆向。 谈起安卓逆向…

C++面试题(叁)---操作系统篇

目录 操作系统篇 1 Linux中查看进程运行状态的指令、查看内存使用情况的指令、 tar解压文件的参数。 2 文件权限怎么修改 3 说说常用的Linux命令 4 说说如何以root权限运行某个程序。 5 说说软链接和硬链接的区别。 6 说说静态库和动态库怎么制作及如何使用&#xff0c;区…

sql:SQL优化知识点记录(六)

&#xff08;1&#xff09;索引优化1 查看一下有没有建立索引&#xff1a; 用到索引中的一个&#xff1a;type中的ref决定访问性能 用到索引中的两个&#xff1a;通过key_len的长度可以看出来&#xff0c;比第一个大一点。或者通过ref&#xff1a;中用到了两个常量const 用到了…

ubuntu系统安装QQ音乐

前言 要问程序员除了编程软件最离不开的最重要的是什么软件&#xff0c;个人觉得就是音乐软件了&#xff0c;所以QQ音乐单独拿出来整理一下&#xff0c;其他的软件放在一起整理一下。“一起长大的约定&#xff0c;那样真心&#xff0c;与你聊不完的曾经&#xff0c;而我已经分…

图像扭曲之万花筒

源码&#xff1a; void kaleidoscope(cv::Mat& src,cv::Mat& dst,double angle,double radius) {dst.create(src.rows, src.cols, CV_8UC3);dst.setTo(0);int cx src.cols / 2;int cy src.rows / 2;//angle PI / 4;double angle2 PI / 4;double sides radius / 3…

【板栗糖GIS】——360浏览器的下载图标隐藏在内部不方便,怎么修改

目录 1. 设置前的本来样子 2. 登录360的皮肤中心 3. 使用se13的经典皮肤 最近edge浏览器最近使用bilibili和notion都非常卡&#xff0c;时不时崩溃&#xff0c;不得不换浏览器使用&#xff0c;试来试去360浏览器最得我心&#xff0c;只不过广告太多&#xff0c;调教也是花了…

复杂性分析与算法设计:解锁计算机科学的奥秘

文章目录 算法复杂性分析的基本概念时间复杂度空间复杂度 常见的算法设计策略1. 分治法2. 贪心法3. 动态规划 算法设计的实际应用1. 网络路由2. 图像处理3. 人工智能 算法的选择和性能分析结论 &#x1f389;欢迎来到数据结构学习专栏~复杂性分析与算法设计&#xff1a;解锁计算…

excel 无法删除有合并单元格的列内容时的替代方法

背景&#xff1a; hp 笔记本电脑&#xff1b;win10 64位&#xff1b;excel 版本 16.0&#xff1b; office 2016自带excel 问题&#xff1a; 把pdf转excel后&#xff0c;由于原 pdf 图表本身的原因&#xff0c;转换后有不规则合并单元格的现象。 而在选择某列进行“删除” &a…

完整开发实现公众号主动消息推送,精彩内容即刻到达

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师…

【爬虫】实验项目三:验证码处理与识别

目录 一、实验目的 二、实验预习提示 三、实验内容 实验要求 基本要求&#xff1a; 改进要求A&#xff1a; 改进要求B&#xff1a; 四、实验过程 基本要求 五、源码如下 六、资料 一、实验目的 部分网站可能会使用验证机制来阻止用户无效登录或者是验证用户不是用程…

vue竖向步骤条

效果图&#xff1a; 弹框组件代码&#xff1a; <template><el-dialog:visible.sync"dialogVisible":append-to-body"true":close-on-click-modal"false":close-on-press-escape"false"titlewidth"8.2rem"custom-c…

Redis 缓存穿透、击穿、雪崩

一、缓存穿透 1、含义 缓存穿透是指查询一个缓存中和数据库中都不存在的数据&#xff0c;导致每次查询这条数据都会透过缓存&#xff0c;直接查库&#xff0c;最后返回空。 2、解决方案 1&#xff09;缓存空对象 就是当数据库中查不到数据的时候&#xff0c;我缓存一个空对象…

力扣:82. 删除排序链表中的重复元素 II(Python3)

题目&#xff1a; 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回 已排序的链表 。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - …

[NSSCTF 2nd] 2023 web方向和misc方向题解 wp

WEB php签到 直接给了源码。 是一个文件上传题目。分析一下源码。 <?phpfunction waf($filename){//黑名单$black_list array("ph", "htaccess", "ini");//得到文件后缀&#xff0c;【有漏洞】$ext pathinfo($filename, PATHINFO_EXTEN…

CData Drivers for SAS xpt Crack

CData Drivers for SAS xpt Crack 使用基于标准的驱动程序&#xff0c;加入数据库、报告工具和自定义程序中的实时SAS xpt(XPORT)数据文件。 与BI分析、报告、ETL工具和自定义解决方案集成。 适用于SAS xpt的CData驱动程序。神奇的功能&#xff1a; BI和分析 我们的驱动程序是将…

VCRUNTIME140_1.dll丢失是怎么回事?有哪些解决方法

今天&#xff0c;我这里与大家分享一个关于VCRUNTIME140_1.dll丢失修复的经验。相信很多网友在日常使用电脑的过程中&#xff0c;都会遇到这样的问题&#xff1a;程序无法运行&#xff0c;提示“缺少VCRUNTIME140_1.dll”的错误。那么&#xff0c;VCRUNTIME140_1.dll丢失是怎么…

[SpringBoot3]视图技术Thymeleaf

七、视图技术Thymeleaf Thymeleaf是一个表现层的模板引擎&#xff0c;一般被使用在Web环境中&#xff0c;它可以处理HTML、XML、JS等文档&#xff0c;简单来说&#xff0c;它可以将JSP作为Java Web应用的表现层&#xff0c;有能力展示与处理数据。这样&#xff0c;同一个模板文…

【OpenCV入门】第六部分——腐蚀与膨胀

文章结构 腐蚀膨胀开运算闭运算形态学方法梯度运算顶帽运算黑帽运算 腐蚀 腐蚀操作可以让图像沿着自己的边界向内收缩。OpenCV通过”核“来实现收缩计算。“核”在形态学中可以理解为”由n个像素组成的像素块“&#xff0c;像素块包含一个核心&#xff08;通常在中央位置&…