html css js实现抽奖,原生(纯)js+html+css实现移动端抽奖转盘系统

2023-10-27

这是我前个月使用纯javascript+html写出的一个抽奖转盘系统,按理来说,我应该在当时做完这个小系统,就应该立即写bike总结才对,但是本人之前没有在网上写博客的习惯,平时总结更加习惯写在纸上,但是现在发现卸载网上可能更好。博客中有许多高手,当你们点进来看到我这篇小总结的时候,还希望多多给我提出建议咯,感谢!其他的话不多说啦,下面进入正题,先亮出我转盘的庐山正面目(ps:这张图是我在网上随便找的,只是简单处理了一下水印)

我的抽奖转盘是水平垂直居中的,也就是处于手机屏幕的正中间,先贴上我html部分的代码

start
恭喜中奖

再贴上css代码

*{

padding: 0;

margin: 0;

}

html{

position: absolute;

overflow: hidden;

}

body{

background-color: white;

overflow: hidden;

}

.random{

width:14.6rem;

height:14.6rem;

position:absolute;

margin: auto;

}

.content{

width:14.6rem;

height:14.6rem;

background: url(bg.jpg);

background-repeat: no-repeat;

background-size: 100%;

background-orign:content-box;

transform:rotate(0deg);

}

.down{

width:2rem;

height: 0.7rem;

background-image: url(down.png);

background-size: 100%;

position: absolute;

left:7rem;

top:0;

}

.start{

width:3rem;

height:3rem;

background-color: red;

position:absolute;

top:5.8rem;

left:5.8rem;

border-radius: 4rem;

-o-border-radius:4rem;

text-align: center;

line-height:3rem;

}

.close{

position: absolute;

top:3rem;

width:4rem;

left:5rem;

text-align: center;

font-weight: bold;

background-color: white;

font-size: 1rem;

display: none;

}

前面的css+html部分的代码只是将我的转盘最安静的时候展现出来

使用原生JavaScript才能真正展现它动如脱兔的一面,先将我的代码贴出来,再讲讲我的思路吧!

random.js文件:

//转盘对象

var Rondom = function(){}

//返回随机的度数

Rondom.prototype.getDeg = function(arr){

var arr = arr;

var len1 = arr.length;//一共有几种奖项

var len2 = 0;//每种奖项有几种可能

var rom2;//抽取奖项的其中一个色块

var deg;//指针只指向的位置

var type;//抽取到的奖品类型

//获取随机数

var rom1 = Math.random();

for(var i = 0; i

if(arr[i].pro >= rom1){

len2 = arr[i].deg.length;

rom2 = Math.round(Math.random() * (len2 -1));

deg = arr[i].deg[rom2];

type = arr[i].type;

break;

}

}

return {'type': type,//返回奖品类型

'deg':deg //返回指针停下来的位置

}

;

}

//转盘旋转

Rondom.prototype.turn = function(objc,objc2,objc3,objc4){

//获取transform的当前旋转位置数组

var arr = ($attrCommon.getStyle(objc,"transform")).split(',');

var arrCos = parseFloat(arr[3]);

var arrSin = parseFloat(arr[1]);

var sinDeg = Math.round(Math.asin(arrSin)*(180/Math.PI));//求当前转盘可能的角度

var cosDeg = Math.round(Math.acos(arrCos)*(180/Math.PI));//求当前转盘可能的角度

var deg = 0;//实际角度

if(arrCos*arrSin > 0){

arrSin > 0 ? deg = cosDeg : deg = 180 - sinDeg;

}else if(arrCos*arrSin < 0){

arrCos > 0 ?deg = sinDeg + 360 : deg = cosDeg;

}else{

arrSin >= 0 ? deg = cosDeg : deg = sinDeg + 360 ;

}

if(objc4){

//$attrCommon.setRotate(objc,objc3,deg);

return deg;

}else{

$attrCommon.setRotate(objc,objc3,deg);

}

}

//向TouchEvent对象订阅start触摸事件

Rondom.prototype.listenerStart = (function(){

window.timeId1;//定义计时器

var n = 0;//计时

var flag = true;//是否点击了转盘

var deg;

var deg2 = 0;//获取上次旋转停留的位置

var m = 0;//旋转次数,可以为小数

var posObj;//获取抽取到的奖项对象

return function(objc,n,objc2,objc3,objc4){

var $this = this;//保存对this的引用

timeId1 = setInterval(function(){

if(flag){

posObj = $this.getDeg(objc4);

deg2 = $this.turn(objc,objc4,posObj.deg,true);//获取上次旋转停下来的位置

objc.style.transform = 'rotate('+0+'deg'+')';//将转盘转回最初的位置

deg = posObj.deg + 720;//转盘每次点击,一共旋转多少度

flag = false;

}

deg2 = $this.turn(objc,objc4,posObj.deg);

n = n + 0.2;

m = m + ((720+posObj.deg)/posObj.deg);//转盘目前旋转了多少度

clearInterval(timeId1);

if(m <= (720+posObj.deg)){

if((m <= 720)){

$this.listenerStart(objc,n,objc2,objc3,objc4);

}else if(m = (720+ posObj.deg)){

deg2 = $this.turn(objc,objc4,posObj.deg,true);//转盘在最后一次旋转前的位置

objc.style.transform = 'rotate('+ 0 +'deg'+')';//将转盘转回初始位置

$this.listenerStart(objc,n,objc2,objc3,objc4);//转盘旋转到指定的角度上

}

}else{

flag = true;

n = 0;

m = 0;

deg2 = 0;

deg = 0;

$this.listenerEnd(objc3,objc2,posObj.type); //结束旋转

posObj = null;

}

},n);

}

})();

//向TouchEvent对象订阅close事件

Rondom.prototype.listenerEnd = function(obj1,obj2,text){

var timeId2 = setTimeout(function(){

obj1.style.display = 'block';

obj2.textContent = 'start';

obj1.textContent = text;

},500);

}

var random = new Rondom();

main.js文件:

//给rem赋予新的值,实现自适应布局

(function (doc, win) {

var docEl = doc.documentElement,

resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',

recalc = function () {

var clientWidth = docEl.clientWidth;

if (!clientWidth) return;

docEl.style.fontSize = 20 * (clientWidth / 320) + 'px';

};

if (!doc.addEventListener) return;

win.addEventListener(resizeEvt, recalc, false);

doc.addEventListener('DOMContentLoaded', recalc, false);

})(document, window);

window.$attrCommon = function(){};//暴露对外接口

(function(){

//读出obj对象的attr属性值

this.getStyle = function(obj,attr)

{

if(obj.currentStyle)

{

return obj.currentStyle[attr];

}

else

{

return document.defaultView.getComputedStyle(obj,false)[attr];

}

},

//给obj对象的transform属性赋值

this.setRotate = function(obj,obj2,obj3){

var n = obj3 + obj2;//转幅

var cosVal = Math.cos(n * Math.PI / 180);//求出旋转角度对应的cos值

var sinVal = Math.sin(n * Math.PI / 180);//求出旋转角度对应的sin值

obj.style.transform = 'matrix(' + cosVal + ','+ sinVal + ','

+ (-sinVal) + ',' + cosVal + ',' + 0 + ',' + 0 + ')';//obj对象旋转

}

}).apply($attrCommon);//对象冒充,降低方法与对象耦合度

(function(){

this.init = function(e,objc1,objc2,objc3,objc4){

try{

var val = touchEvent.touchend(e,objc2);

if(val == 'start'){

random.listenerStart(objc1,1,objc3,objc2,objc4);

}

}

catch(err){

alert('发生错误!');

}

}

}).apply($attrCommon);

(function(){

this.setTop = function(objc1,objc2){

var docEl = document.documentElement,

resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',

recalc = function () {

var height1 = parseFloat(($attrCommon.getStyle(objc1,'height')).split('p')[0]);

var height2 = parseFloat(($attrCommon.getStyle(objc2,'height')).split('p')[0]);

var width1 = parseFloat(($attrCommon.getStyle(objc1,'width')).split('p')[0]);

var width2 = parseFloat(($attrCommon.getStyle(objc2,'width')).split('p')[0]);

var clientHeight = docEl.clientHeight;

var clientWidth = docEl.clientWidth;

if (!clientHeight || !clientWidth) return;

objc1.style.top = (clientHeight/2- height1/2) + 'px';

objc2.style.top = (clientHeight/2 - height2/2) + 'px';

objc1.style.left = (clientWidth/2- width1/2) + 'px';

objc2.style.left = (clientWidth/2 + width2/4) + 'px';

};

if (!document.addEventListener) return;

window.addEventListener(resizeEvt, recalc, false);

document.addEventListener('DOMContentLoaded', recalc, false);

}

}).apply($attrCommon);

最后在html页面中加上:

var start = document.getElementById('start');

var randomDiv = document.getElementById('randomDiv');

var content = document.getElementById('content');

var close = document.getElementById('close');

var down = document.getElementById('down');

//转盘中一共有四种可能性,每种可能性的概率为0.1,0.2,0.3,0.4,一共为1

var arr = [{'pro': 0.1,'deg': [96,316],'type': '一等奖'},{'pro': 0.3,'deg': [40,274,176],'type':'二等奖'},

{'pro': 0.6,'deg': [18,297,197,117],'type':'三等奖'},{'pro': 1,'deg': [68,342,236,148],'type':'幸运奖'}];

//content.style.transform = 'rotate(316deg)';

var $attrcommon = new $attrCommon();//实例化random.js接口

start.addEventListener('touchend',function(e){

$attrCommon.init(e,content,close,start,arr);

},false);

$attrCommon.setTop(randomDiv,down);

好啦,贴出这么多代码,相信大家也没耐心看下去。先让我来讲讲我的主要思路吧。我在做这个转盘的时候,是希望能够作为一个插件来使用。所以基于考虑抽奖系统的可复用性,一开始我做的时候,运用的是设计模式的单一职责原则,尽量把职责单一化,粒度化,所以我将这个系统主要分为三个对象,random对象(转盘对象)和TouchEvent对象(触摸对象)和obj对象(传入的dom对象需要用到的方法),而且将它们分别放在random文件和touch文件中和main文件中,便于管理。

random对象需要考虑转盘中一共有多少种奖项,在我这里是四种,每种奖项有几个色块。最开始我做的时候,思路很单一,很直接地将表面看到的东西写出来,没有考虑人为可控地自定义每个奖项发生的概率,而是直接由给出图片的来决定,换句话说,图片上每个奖项有几个色块,色块大小有多少决定了奖项被抽中的概率。这样其实不是很好,设计人员给的图片已经是定死的,如何灵活的自定义概率,前端其实就像变魔术,我们只需要将最终需要呈现的效果实现就好,过程可以更加有趣一点。于是,我不看转盘图片上有每个奖项有几个色块,直接定义每个奖项的被抽中的概率范围,这里我是将一等奖设置在0到0.1之间,每次随机生成一个小于1的随机数,看看随机数处于哪个区间,这样决定被抽中的奖项。既然要做的逼真一些,那么就不能固定转到同一个色块,让指针最终停留在被抽的奖项的任意一个随机的色块。还有一个问题是,开始我让转盘匀速转动,给定它一定时间,达到时间后直接挺下来。但这样设定,不符合现实中的场景,我们转动一个转盘,肯定是让它速度越来越慢,最终停下来。所以转盘的转动由时间来控制,最终变成初始速度来决定。

我这里的touch对象是转盘正中间的圆形按钮,如果按钮上的文本是start,此时点击,转盘会转动,文本由start变成close,当转盘是停下来,文本又变回start。

我这里的方法全部都是封装好的,我在这里,自定义了window.$attrCommon = function(){};用来暴露对外接口,除了对象的属性和方法,其他的方法全部(function()).apply($attrCommon),这样既可以避免全局作用域被污染,还能封装,使用apply,也可以降低方法和对象的耦合度。

打开App,阅读手记

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

html css js实现抽奖,原生(纯)js+html+css实现移动端抽奖转盘系统 的相关文章

  • TI DSP TMS320C66x学习笔记之VLIB测试数据(三)

    VLIB是TI提供的针对C6x优化过的视觉库 下载地址 http software dl ti com libs vlib latest index FDS html 提供40多个核心函数 主要实现以下功能 Background Model
  • SpringBoot+vue旅游项目总结

    Springboot vue旅游项目小总结 此项目为一个springboot vue入门级小项目 视频地址为 https www bilibili com video BV1Nt4y127Jh 业务简单 对提升业务能力没什么大的帮助 更多的
  • 开始→运行→输入的命令集锦

    gpedit msc 组策略 sndrec32 录音机 nslookup ip地址侦测器 explorer 打开资源管理器 logoff
  • 最后一位

    题目名称 最后一位 小明选择了一个正整数X 然后把它写在黑板上 然后每一天他会擦掉当前数字的最后一位 直到他擦掉所有数位 在整个过 程中 小明会把所有在黑板上出现过的数字记录下来 然后求出他们的总和sum 例如X 509 在黑板上出现过的数
  • vue打包放服务器显示代码,解决vue-cli3打包代码后,上线服务器后白屏问题

    前沿 因为最近vue刚刚发版了最新版本的vue cli3 而最近刚刚好有个项目要迁移到vue 所以经过讨论 大家一起入坑VUE 然后我也刚好可以练手刚学一周的vue 结合TypeScript和vuex等全家桶的框架 后期 噗呲噗呲的大家在开
  • C++实现快速排序(源代码)

    快速排序的基本思想是 通过一趟排序将要排序的数据分割成独立的两部分 其中一部分的所有数据都比另外一部分的所有数据都要小 然后再按此方法对这两部分数据分别进行快速排序 整个排序过程可以递归进行 以此达到整个数据变成有序序列 快速排序是一种不稳
  • 一阶滞后环节matlab,一个一阶惯性带有滞后环节的PID仿真程序

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 我照着网上的程序自己改出来的程序是这样的 clc clear ts 0 001 采样时间 sys tf 53 19926 100 ioDelay 540 tf是传递函数 用来实现G s 在自动控
  • 一种基于强化学习的自动变道机动方法

    文章目录 摘要 前言 相关的工作 方法论 动作空间 奖励函数设计 Q学习 仿真结果 结论 摘要 变道是一项至关重要的车辆操作 需要与周围车辆协调 建立在基于规则的模型上的自动换道功能可能在预定义的操作条件下表现良好 但在遇到意外情况时可能容
  • 海思芯片pcie启动——pcie_mcc驱动框架的booter程序分析

    1 booter程序介绍 1 源码目录 pcie mcc multi boot example boot test c 2 调用命令 booter start device 3 booter程序的作用 在主片将pcie启动相关的驱动加载完成
  • centos7 安装jdk1.8

    一 安装环境 虚拟机centos7 二 安装步骤 linux环境下软件的安装有两种类型 yum install 和wget gz 安装包的格式 建议不管安装什么软件方式 能用wget解压安装包安装就用这种方式安装 1 下载安装包 wget
  • BUUCTF【Web】Secret File

    知识点 文件包含漏洞 PHP伪协议 进入靶场后 发现是一个文字界面没有任何特点 习惯性的右键查看源代码 发现有一个PHP文件 点击进行访问后 发现有一个链接但是点击链接后没有发现任何东西 此时右键查看原代码也没有发现东西 但是可以肯定的是突
  • ERP收付款的操作与设计--开源软件诞生22

    赤龙ERP收款付款讲解 第22篇 用日志记录 开源软件 的诞生 进入地址 点亮星星 祈盼着一个鼓励 博主开源地址 码云 https gitee com redragon redragon erp GitHub https github co
  • 4,引擎初始化--(5)初始化actor--5,初始化各个关卡中的各个actor-PostInitializeComponents()

    PostInitializeComponents 是actor最初处于完整状态的地方 所以 在这里经常编写actor在游戏开始时的初始化相关代码 此时 loadmap 加载完毕 actor加载完毕并初始化 world处于可玩状态 同时也有了
  • [搭建CLI效率工具] Rollup + TypeScript 搭建CLI工程

    环境搭建 工欲善其事必先利其器 使用Rollup搭建Typescript开发环境 毕竟Typescript是大势所趋并且Rollup相比较webpack对于node模块来说比较优化 创建项目目录并初始化 mkdir
  • vue中自定义链接的href内容,设置动态链接,动态添加请求头

    在http js页面定义好了需要动态添加的接口请求头 OPEN UR 如下 列如下 需要给点击下载模板时的 a 标签动态添加请求头和接口 html部分 a size middle class middleBtn 下载模板 a js部分 im
  • 如何更改element-ui自定义主题

    element ui总结 一 如何更改element ui的主题 1 在src下创建element variables scss文件 改变主题色变量 color primary a0c69d 改变 icon 字体路径变量 必需 font p
  • 树莓派安装openCV做图像识别

    点击上方 小白学视觉 选择加 星标 或 置顶 重磅干货 第一时间送达 本文转自 新机器视觉 有时候我们会使用树莓派和摄像头去做图像识别 在树莓派和LINUX系统中最常用opencv去做图像识别 这次来介绍下树莓派安装opencv和用树莓派做
  • SD卡存储程序

    把采集的ad的数据存到SD卡中 int main void u16 fwrite counter 0 unsigned char Temp 11 data ok flag 1 for i 0 i lt 12 i ad i 0 for i 0
  • vtk创建点

    使用vtk库创建三维空间中的点 引言 开发环境 示例一 项目结构 实现代码 运行效果 示例二 项目结构 实现代码 运行效果 总结 引言 本文仅适合初学者 本文不提供vtk动态库的生成 以及在QtCreator中的引进vtk时的配置 本文先由

随机推荐

  • 牛人项目失败的总结

    tom lt 遇到的失败项目比较多 让人郁闷 仔细分析原因 主要在于 1 项目开始需求不明确 领导决定动手 就开始启动项目 造成和客户需要差距太大 导致失败 2 需求变更没有控制 客户提出新的需求 或者改变原来的需求 没有一个好的控制流程
  • 【模式识别4】YOLO目标检测数据集xml格式转txt格式

    YOLO目标检测数据集xml格式转txt格式 1 转换前的xml格式 2 xml格式转txt格式代码 2 1 源代码 2 2 需要修改的地方 3 转换后的txt格式 代码资源 voc2txt py 1 转换前的xml格式 如果我们使用Lab
  • 男人必读 --看了永不后悔,女人想看也可以进去……

    1 事业永远第一 虽然金钱不是万能的 但没有钱是万万不能的 虽然这句话很俗 但绝对有道理 所以30岁之前 请把你大部分精力放在你的事业上 事业远比爱情重要 如果说事业都不能永恒 那么爱情只能算是昙花一现 记 得那首 没有钱你会爱我吗 的歌吗
  • 基于Koa的微信第三方平台使用及搭建说明(一)

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 前言 公司内部使用说明文档 记录一下 目的在于使内部人员了解和熟悉项目 不在于搭建教程 看不明白的就别看了 一 关于 Node Node是什么 官网上给出的定义是 一个搭建
  • Mac 好用的shell终端

    1 搜索关键词 my zsh 2 http ohmyz sh
  • 【docker】docker-compose实战之MySQL安装与配置

    唠嗑部分 首先说一下 MySQL是否适合容器化 数据库首先要解决数据的持久化问题 以确保服务宕机之后数据不会丢失 docker提供的数据卷虽然可以让数据保存在宿主机上 但是容器的 volumn数据卷的设计是围绕 Union FS镜像层提供持
  • scratch颜色实验(R+G+B)/自制素材/少儿编程scratch教研教案课件课程素材脚本

    scratch颜色实验 wmv
  • 在线接口文档管理工具推荐,支持在线测试,生成漂亮的http文档

    易文档 英文名叫easydoc 是新出来的文档管理平台 跟市面的那些有所不同 这个不管是编写体验还是预览 专业性和美观性都会大大超越其他的 看下他的预览效果 市面很多http接口文档的编写都是直接写markdown文档 这种编写起来特别麻烦
  • VBA 向文件写入编码为UTF-8的数据

    Sub Test 需要引入 ActiveX Data Objects ADO 组件 即 Microsoft ActiveX Data Objects 2 5 Library 或者 Microsoft ActiveX Data Objects
  • qt右键弹出菜单的一些实现方法

    在qt中 关于右键弹出菜单 有几种实现方法 1 在窗口初始化时 修改指定控件的右键菜单策略 然后把右键点击信号和某个槽函数连接 设置btnNew按钮的右键菜单策略 ui gt btnNew gt setContextMenuPolicy Q
  • 有趣的telnet站点

    这个都能做电影 不知道他们花了多长的时间 telnet towel blinkenlights nl 下面这个是其他的一些站点 我没有看过 留个链接 http www telnet org htm places htm
  • 记第一次拆机

    两周前的周日 也不知道抽了什么风萌生了拆笔记本电脑的想法 可能是由于从购买之后风扇都没清理过的原因吧 笔记本电脑品牌联想 型号G480 2013年大一暑假购置的机子 也就是普通的上网本吧 玩游戏确实有点卡 比如剑灵 好了 言归正传 下面开始
  • 卡西欧计算机的闹铃怎么取消,卡西欧g-shock怎么关闹钟

    卡西欧g shock怎么关闹钟 连续按mode按键 通常是左下角按键 直至液晶屏幕出现al1 al2 al3等等字样 然后 第二显示屏会显示 on 按 adjust 就可以改为 of 就关闭了 卡西欧g shock闹钟怎么设置 1 按MOD
  • 一文搞定Postman(菜鸟必看)

    什么是Postman Postman是一个可扩展的 API 测试工具 可以快速集成到 CI CD 管道中 它于 2012 年作为 Abhinav Asthana 的一个副项目启动 旨在简化测试和开发中的 API 工作流程 API 代表应用程
  • java高并发多线程架构_java架构师指南 高并发和多线程的区别

    高并发和多线程 总是被一起提起 给人感觉两者好像相等 那它们之间究竟有什么区别呢 1 多线程 多线程是java的特性 也是java架构师必须掌握的一项技术 因为现在cpu都是多核多线程的 可以同时执行多个任务 为了提高JVM的执行效率 Ja
  • 搭建Obsidian+picGo+Lsky Pro图床

    搭建Obsidian picGo Lsky Pro图床 0 前言 去年心血来潮买了个小主机 搭建了家庭服务器 安装了PVE系统 散热拉胯 性能不足目前只创建了个黑群晖系统 搭建一个图床 方便日常笔记工作 1 软件 1 1 Obsidian
  • 浅谈App的性能优化

    浅谈App的性能优化 2018 01 02 说到 Android 系统手机 大部分人的印象是用了一段时间就变得有点卡顿 有些程序在运行期间莫名其妙的出现崩溃 打开系统文件夹一看 发现多了很多文件 然后用手机管家 APP 不断地进行清理优化
  • Git第十讲 Git如何正确使用log快速查找内容/提交

    在Git中 你可以使用不同的命令来快速查找指定内容或指定提交 下面我将介绍两种常用的方法 快速查找指定内容 要快速查找包含特定内容的文件或代码行 可以使用 git grep 命令 它类似于常见的 grep 命令 但是专门用于搜索Git仓库中
  • 以太坊交易确认数如何获取

    以太坊和比特币一样 都有一个最长链的概念 因此也有一个交易确认数的概念 当一个以太坊交易所在区块被新加入区块链时 该交易的确认数为1 之后每增加一个区块 该交易的确认数加1 显然 一个以太坊交易的确认数越多 就意味着该交易在区块链中埋的越深
  • html css js实现抽奖,原生(纯)js+html+css实现移动端抽奖转盘系统

    这是我前个月使用纯javascript html写出的一个抽奖转盘系统 按理来说 我应该在当时做完这个小系统 就应该立即写bike总结才对 但是本人之前没有在网上写博客的习惯 平时总结更加习惯写在纸上 但是现在发现卸载网上可能更好 博客中有