转盘抽奖功能(附加代码)

news2024/12/16 6:05:47

写在开头

上期代码主要实现PC端电商网站商品放大效果,本期就来实现积分随机抽奖效果,开发久了很多功能都是通过框架组件库来完成,但是如果组件满足不了开发需求,还需要开发人员手动封装组件,专门出这样一期文章,通过原生js实现一些特定功能,功能也比较简单,也是想借助这样一个简单的功能,然后来帮助大家了解我们JavaScript,在前端中的作用,另外也培养下我们的代码思维,那我们本次就通过由简单到复杂循序渐进,这份专栏中我们会带领大家用前端实现拼图、无缝轮播图、图片瀑布流、读心术小游戏等等有趣的小功能,纯前端语言实现,都会陆续带给大家。

功能介绍

转盘抽奖功能,正常开发中中奖概率,抽奖次数都是后台数据返回的,就像你拼西西抽红包,因为是纯前端完成,概率完全随机数,页面逻辑代码中注释很完善,请看下图代码

页面创建

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>随机抽奖</title>
    <link rel="stylesheet" href="demo.css">
</head>
<body>
    <!-- 整体 -->
    <div class="main">
        <!-- 抽奖区域 -->
        <div class="content-container">
            <!-- 抽奖项 -->
            <div class="price-list">
                <img src="../img/prize_1.png" alt="">
                <span>IphoneX19</span>
            </div>
            <div class="price-list">
                <img src="../img/prize_2.png" alt="">
                <span>金币20</span>
            </div>
            <div class="price-list">
                <img src="../img/prize_3.png" alt="">
                <span>华为Mate 90 一部</span>
            </div>
            <div class="price-list">
                <img src="../img/prize_4.png" alt="">
                <span>金币10</span>
            </div>
            <div class="price-list">
                <img src="../img/prize_5.png" alt="">
                <span>谢谢参与</span>
            </div>
            <div class="price-list">
                <img src="../img/prize_6.png" alt="">
                <span>手机优惠券</span>
            </div>
            <div class="price-list">
                <img src="../img/prize_7.png" alt="">
                <span>电脑优惠券</span>
            </div>
            <div class="price-list">
                <img src="../img/prize_8.png" alt="">
                <span>U</span>
            </div>
            <!-- 中间区域 -->
            <div class="hander-container">
                <div class="inner-container">
                    <img src="../img/center_1.png" alt="" class="hander-left">
                    <div class="hander-container-middle">
                        还可以抽奖 <span class="price-number">0</span></div>
                    <div class="hander-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="./demo.js"></script>
</body>
</html>

样式搭建

* {
    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%);
}
/* 奖项区域 */
.price-list {
    width: 270px;
    height: 100px;
    position: absolute;
    padding: 5px;
    text-align: center;
    background-color: #622230;
    border: 1px solid #722536;
    border-radius: 5px;
    box-sizing: border-box;
}

.price-list>img {
    max-height: 75px;
    position: absolute;
    left: 30px;
    top: 15px;
}

.price-list>span {
    font-size: 19px;
    color: #ffb100;
    font-weight: bold;
    position: absolute;
    left: 102px;
    top: 36px;
    width: 164px;
}

.price-list:nth-child(1) {
    top: 22px;
    left: 26px;
}

.price-list:nth-child(2) {
    top: 22px;
    left: 302px;
}

.price-list:nth-child(3) {
    top: 22px;
    right: 26px;
}

.price-list:nth-child(4) {
    top: 129px;
    right: 26px;
    width: 100px;
    height: 200px;
}

.price-list:nth-child(4)>img,
.price-list:nth-child(8)>img {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    top: 15px;
}

.price-list:nth-child(4)>span,
.price-list:nth-child(8)>span {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    bottom: 36px;
    top: auto;
}

.price-list:nth-child(5) {
    bottom: 22px;
    right: 26px;
}

.price-list:nth-child(6) {
    bottom: 22px;
    left: 302px;
}

.price-list:nth-child(7) {
    bottom: 22px;
    left: 26px;
}

.price-list:nth-child(8) {
    top: 129px;
    left: 26px;
    width: 100px;
    height: 200px;
}

/* 中间抽奖区域 */
.hander-container {
    width: 614px;
    height: 198px;
    background-image: url('../img/middle-bg.png');
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%,-50%);
}

.inner-container {
    display: table-cell;
    vertical-align: middle;
    padding: 0 20px;
    padding: 50px;
}

.hander-left {
    float: left;
    vertical-align: middle;
}

.hander-container-middle {
    float: left;
    color: #ffd200;
    font-size: 30px;
    font-weight: bold;
    margin: 17px 0 0 18px;
}

.hander-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;
}

主要逻辑

/* 
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 再来一次按钮事件绑定 
4:  定义runGame函数
5: timer定时器bug修复
 */
(function(){
    // 开始抽奖按钮
    var startBtn = document.querySelector('.hander-container-btn')
    // 奖项
    var priceList =document.querySelectorAll('.price-list')
    // 弹窗区域
    var dialogContainer = document.querySelector('.dialog-container')
    // 弹窗内容区域
    var priceContent = document.querySelector('.dialog-container .content')
    var index = -1
    var timer = null
    var number = 5
    var currentIndex = null
    // 弹窗关闭按钮
    var closeBtn = document.querySelector('.close')
    // 弹窗按钮再来一次
    var confirmBtn = document.querySelector('.dialog-main-footer .button')
    // 剩余抽奖次数
    var priceNumber = document.querySelector('.price-number')

    // 初始化
    var init = function(){
        priceNumber.innerHTML = number
        initEvent()
    }
    // 初始化函数
    var initEvent = function(){
        // 添加监听事件
        startBtn.addEventListener('click',onStartBtnClick)
        closeBtn.addEventListener('click',onCloseBtnClick)
        confirmBtn.addEventListener('click',onConfirmBtnClick)
    }
    // 开始抽奖
    var onStartBtnClick = function(){
        if(timer) return
        index = -1
        if(number === 0) return
        runGame()
    }
    // 转盘转动
    var runGame = function(){
        // 获取随机数
        var ranDom = Math.floor(Math.random() * 6000 + 3000)
        timer = setInterval(function(){
            ranDom -= 200
            if(ranDom < 200){
                // 小于200停止转盘
                clearInterval(timer)
                timer = null
                // 打开弹窗
                openDialog()
                return
            }
            currentIndex = ++index % priceList.length
            priceList.forEach(function(el){
                // 先移除背景滚动效果
                el.classList.remove('active')
            })
            // 给滚动项加上背景高亮背景
            priceList[currentIndex].classList.add('active')
        },60)
    }
    // 打开弹窗
    var openDialog = function(){
        priceNumber.innerHTML = --number
        if(number === 0){
            document.querySelector('.dialog-main-footer .button').innerHTML = '确定'

        }
        dialogContainer.style.display = 'block'
        var spanText = document.querySelector('.active span').innerHTML
        if(spanText.includes('谢谢参与')){
            priceContent.innerHTML = '很遗憾您没有中奖'
        }else {
            priceContent.innerHTML = '恭喜您获得' + spanText
        }
    }
    // 关闭弹窗
    var onCloseBtnClick = function(){
        dialogContainer.style.display = 'none'
    }
    // 弹窗确认按钮 && 再来一次
    var onConfirmBtnClick = function(){
        index = -1
        dialogContainer.style.display = 'none'
        if(number === 0 || timer) return
        runGame()
    }

    init()
})()

结尾总结

点击抽奖按钮之后,里面涉及的功能有些许复杂,需要一步步捋下来,遇到问题就一步步解决,给一个参考图

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

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

相关文章

【CSS in Depth 2 精译_075】12.2 Web 字体简介 + 12.3 谷歌字体的用法

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 12 章 CSS 排版与间距】 ✔️ 12.1 间距设置 12.1.1 使用 em 还是 px12.1.2 对行高的深入思考12.1.3 行内元素的间距设置 12.2 Web 字体 ✔️12.3 谷歌字体 ✔️12.…

ARM嵌入式学习--第七天(GPT)

GPT -介绍 GPT有一个32位向上计数器&#xff0c;定时计数器值可以使用外部引脚上的事件捕获到寄存器中&#xff0c;捕获触发器可以被编程为上升沿和下降沿。GPT还可以在输出比较引脚上生成事件&#xff0c;并在定时器达到编程值时产生中断。GPT有一个12位预分频器&#xff0c;…

搭建Tomcat(一)---SocketServerSocket

目录 引入1 引入2--socket 流程 Socket&#xff08;应用程序之间的通讯保障&#xff09; 网卡(计算机之间的通讯保障) 端口 端口号 实例 client端 解析 server端 解析 相关方法 问题1&#xff1a;ServerSocket和Socket有什么关系&#xff1f; ServerSocket Soc…

SpringBoot快速使用

一些名词的碎碎念: 1> 俩种网络应用设计模式 C/S 客户端/服务器 B/S 浏览器/服务器 俩者对比: 2> 集群和分布式的概念 集群: 分布式: 例子: 一个公司有一个人身兼多职 集群: 招聘N个和上面这个人一样身兼多职 分布式: 招聘N个人,分担上面这个人的工作,进行工作的拆分. 工…

【含开题报告+文档+PPT+源码】基于SpringBoot的开放实验管理平台设计与实现

开题报告 设计开放实验管理平台的目的在于促进科学研究与教学的融合。传统实验室常常局限于特定地点和时间&#xff0c;而开放平台可以为学生、教师和研究人员提供一个便捷的交流与共享环境。通过在线平台&#xff0c;他们可以分享实验资源、交流经验&#xff0c;从而促进科学…

分布式 漏桶算法 总结

前言 相关系列 《分布式 & 目录》《分布式 & 漏桶算法 & 总结》《分布式 & 漏桶算法 & 问题》 概述 简介 LBA Leaky Bucket Algorithm 漏桶算法是一种流行于网络通信领域的流量控制/频率限制算法。漏桶算法的核心原理是通过一个概念上的“漏桶”来…

linux glances vs top

一、安装 apt-get install glances glances top显示效果&#xff1a;

CTF知识集-PHP特性

title: CTF知识集-PHP特性 写在开头可能会用到的提示 call_user_func 调用的函数可以不区分大小写preg_match过滤存在长度溢出&#xff0c;长度超过100w检测失效。str_repeat(‘show’,250000); 生成100w个字符preg_match是无法处理数组的&#xff0c;例如:preg_match( n u m…

Hadoop运行Mapreduce问题集锦——Ubuntu虚拟机配置

一、端口访问问题 问题描述 运行任务前一直重连。具体来说&#xff0c;错误发生在尝试从czs-virtual-machine虚拟机的127.0.1.1地址连接到同一台机器的8032端口时&#xff0c;连接被拒绝。 如下&#xff1a; 2024-11-17 23:05:45,800 INFO retry.RetryInvocationHandler: java…

【经验分享】搭建本地训练环境知识点及方法

最近忙于备考没关注&#xff0c;有次点进某小黄鱼发现首页出现了我的笔记还被人收费了 虽然我也卖了一些资源&#xff0c;但我以交流、交换为主&#xff0c;笔记都是免费给别人看的 由于当时刚刚接触写的并不成熟&#xff0c;为了避免更多人花没必要的钱&#xff0c;所以决定公…

流程引擎Activiti性能优化方案

流程引擎Activiti性能优化方案 基于关系型数据库层面优化 MySQL建表语句优化 Activiti在MySQL中创建默认字符集为utf8&#xff08;即utf8mb3&#xff09;格式&#xff0c;本文将默认字符集设置为utf8mb4&#xff0c;排序规则为utf8mb4_general_ci&#xff0c;并修改变量等类…

Unix 传奇 | 谁写了 Linux | Unix birthmark

注&#xff1a;本文为 “左耳听风”陈皓的 unix 相关文章合辑。 皓侠已走远&#xff0c;文章有点“年头”&#xff0c;但值得一阅。 文中部分超链已沉寂。 Unix 传奇 (上篇) 2010 年 04 月 09 日 陈皓 了解过去&#xff0c;我们才能知其然&#xff0c;更知所以然。总结过去…

TimerPickerDialog组件的用法

文章目录 1 概念介绍2 使用方法3 示例代码我们在上一章回中介绍了Snackbar Widget相关的内容,本章回中将介绍TimePickerDialog Widget.闲话休提,让我们一起Talk Flutter吧。 1 概念介绍 我们在这里说的TimePickerDialog是一种弹出窗口,只不过窗口的内容固定显示为时间,它主…

大模型系列4--开源大模型本地部署到微调(WIP)

背景 一直想真正了解大模型对硬件资源的需求&#xff0c;于是准备详细看一篇视频&#xff0c;将核心要点总结记录下。本文内容参考视频&#xff1a;保姆级教程&#xff1a;6小时掌握开源大模型本地部署到微调&#xff0c;感谢up主 训练成本 训练 > 微调 > 推理训练GPT…

现代密码学总结(上篇)

现代密码学总结 &#xff08;v.1.0.0版本&#xff09;之后会更新内容 基本说明&#xff1a; ∙ \bullet ∙如果 A A A是随机算法&#xff0c; y ← A ( x ) y\leftarrow A(x) y←A(x)表示输入为 x x x ,通过均匀选择 的随机带运行 A A A,并且将输出赋给 y y y。 ∙ \bullet …

Python中opencv的一些函数及应用

Sobel 算子函数 功能&#xff1a; Sobel 算子用于计算图像的梯度&#xff08;变化率&#xff09;&#xff0c;常用于边缘检测。它通过对图像应用一个基于一阶导数的滤波器来强调图像中的边缘部分&#xff0c;特别是水平和垂直方向上的边缘。通过计算图像的梯度&#xff0c;可以…

【docker】springboot 服务提交至docker

准备docker &#xff08;不是docker hub或者harbor&#xff0c;就是可以运行docker run的服务&#xff09;&#xff0c;首先确保docker已经安装。 本文以linux下举例说明&#xff1a; systemctl stats docker ● docker.service - Docker Application Container EngineLoaded…

XDOJ 877 图的深度优先遍历

题目&#xff1a;图的深度优先遍历 问题描述 已知无向图的邻接矩阵&#xff0c;以该矩阵为基础&#xff0c;给出深度优先搜索遍历序列&#xff0c;并且给出该无向图的连通分量的个数。在遍历时&#xff0c;当有多个点可选时&#xff0c;优先选择编号小的顶点。&#xff08;即…

大屏开源项目go-view二次开发1----环境搭建(C#)

最近公司要求做一个大屏的程序用于展示公司的产品&#xff0c;我以前也没有相关的经验&#xff0c;最糟糕的是公司没有UI设计的人员&#xff0c;领导就一句话要展示公司的产品&#xff0c;具体展示的内容细节也不知道&#xff0c;全凭借自己发挥。刚开始做时是用wpf做的&#x…

摆脱B端UI框架的桎梏,首先从布局开始

在 B 端开发中&#xff0c;UI 框架虽带来便利&#xff0c;但也可能形成桎梏。要摆脱这种束缚&#xff0c;首先从布局着手是个明智之举。传统的 B 端 UI 框架布局可能较为固定&#xff0c;缺乏灵活性。我们可以尝试创新的布局方式&#xff0c;如响应式设计&#xff0c;适应不同屏…