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

这是我前个月使用纯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,也可以降低方法和对象的耦合度。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值