首先我们来看一下效果:
说明:在这个案例中,停止位置的输入范围是0-7,代表8个停止位置(顺时针排列),然后我们后台设置的中奖位置是1。
8个停止位置的分布图:
0 1(中奖位置) 2
7 3
6 5 4
下面是相关的代码,相信详细的注释能够帮助你理解!!!
HTML:
<div id="box">
<div id="header">
<span>停止位置:</span>
<input type="text" value="0" id="txt">
</div>
<div id="comment"><span>输入值的范围:0-7,默认停止位置:0</span></div>
<div id="main">
<div class="num"><img src="./xingyun.jpg" alt=""></div>
<div class="num"><img src="./xingyun.jpg" alt=""></div>
<div class="num"><img src="./xingyun.jpg" alt=""></div>
<div class="num"><img src="./xingyun.jpg" alt=""></div>
<div class="num" id="mid"><input type="button" value="抽奖" id="start"></div>
<div class="num"><img src="./xingyun.jpg" alt=""></div>
<div class="num"><img src="./xingyun.jpg" alt=""></div>
<div class="num"><img src="./xingyun.jpg" alt=""></div>
<div class="num"><img src="./xingyun.jpg" alt=""></div>
</div>
</div>
CSS:
* {
margin: 0;
padding: 0;
}
html,
body {
width: 100%;
height: 100%;
}
#box {
width: 100%;
height: 100%;
background-color: silver;
}
#header {
width: 600px;
height: 70px;
margin: 0 auto;
text-align: center;
padding-top: 30px;
background-color: aquamarine;
opacity: 0.65;
}
#header span {
line-height: 35px;
font-size: 35px;
color: black;
}
#header input {
height: 40px;
font-size: 35px;
}
#comment{
width: 600px;
height: 50px;
margin: 0 auto;
color: black;
background-color: aquamarine;
opacity: 0.65;
text-align: center;
font-size: 30px;
}
#main {
width: 600px;
height: 600px;
margin: 0 auto;
}
.num {
width: 200px;
height: 200px;
float: left;
opacity: 0.3;
}
img {
width: 100%;
height: 100%;
}
#mid {
opacity: 0.7;
}
#mid input {
width: 100%;
height: 100%;
background-color: red;
font-size: 40px;
color: aliceblue;
}
JS:
//定义一个定时器的句柄
var interval = null;
//定义点击开始以后,定时器执行的时间间隔
var inTime = 100;
//获取1-8的div
var divNum = document.getElementsByClassName('num');
//把获取到的数组重新排序,因为得到的divNum长度为9,但是最中间的那个“开始”盒子不需要,而且divL里面的class对象顺序不符合要求
var divList = [];
for (let i = 0; i < 3; i++) {
divList.push(divNum[i])
}
divList[3] = divNum[5];
divList[4] = divNum[8];
divList[5] = divNum[7];
divList[6] = divNum[6]
divList[7] = divNum[3];
//自动转圈函数
function animation() {
var index = 0;
interval = setInterval(function () {
//divList[index].style.opacity = 1;注意,这句不能写在这里,因为在最后,index会等于8,但是divList数组最大下标为7
if (index > 7) {
index = 0;
divList[7].style.opacity = 0.5;
} else if (index != 0) {
divList[index - 1].style.opacity = 0.5;
}
//给盒子的透明度设置为1
divList[index].style.opacity = 1;
index++;
}, 1000)
}
//页面加载以后,先自动转圈
window.onload = animation;
//为盒子里面的“开始”按钮注册点击事件
var inputStart = document.getElementById("start");
var valTxt = document.getElementById("txt");
inputStart.onclick = function () {
//首先判断用户输入的停止位置的值是否合乎格式,默认的位置为0
if (valTxt.value.length == 1 && parseInt(valTxt.value) >= 0 && parseInt(valTxt.value) <= 7) {
//禁用按钮
inputStart.disabled="disabled";
inputStart.value = "抽奖中..."
//取消页面加载以后设置的定时器(也就是取消自动转圈)
clearInterval(interval);
//先更改所有的盒子透明度
for (let i = 0; i < divList.length; i++) {
divList[i].style.opacity = 0.5;
}
//设置更快的定时器,时间间隔为inTime=0.1s
var index = 0;
interval = setInterval(function () {
//divList[index].style.opacity = 1;注意,这句不能写在这里,因为在最后,index会等于8,但是divList数组最大下标为7
if (index > 7) {
index = 0;
divList[7].style.opacity = 0.5;
} else if (index != 0) {
divList[index - 1].style.opacity = 0.5;
}
//给盒子的透明度设置为1
divList[index].style.opacity = 1;
index++;
}, inTime)
//快速转圈两秒以后,执行stop函数
//思考一个问题?两秒以后,快速转圈还会继续转吗?
//答案:会的,两秒后执行延时器里面的操作以后,还会继续执行定时器里面的操作
setTimeout(function () {
stop(parseInt(valTxt.value));
}, 2000)
} else {
alert("尊敬的用户,请正确输入停止位置的值!");
}
//让转动停下来,接收的形参为停止位置的值
function stop(luckPosition) {
//清除定时器
clearInterval(interval)
//得到opacity为1的那个盒子的位置current
var current = -1;
for (let i = 0; i < divList.length; i++) {
if (divList[i].style.opacity == 1) {
current=i;
}
}
//注意:current+1
stopLuck(luckPosition,current+1,inTime,10)//inTime是点击“开始”以后,定时器执行的时间间隔,大小为100,也就是转圈的速度
}
//
function stopLuck(luckPosition,index,time,stepTime) {
//设置一个延时器,0.1s以后执行(传进来的time=100)
//思考一个问题,为什么这里也需要设置一个延时器,而且最开始时候,延迟时间time为传进来的inTime=100?答案在下面的注释中!
setTimeout(function () {
//重置opacity
//这里需要注意两个问题?
//第一个问题:不明白为什么这里需要重置opacity,因为在“开始”按钮注册点击事件里面的定时器函数语句会重置opacity,这里再重置
//是多此一举,其实这里重置opacity是为了在递归该函数时候,重置opacity
//第二个问题:第一次执行stopLuck函数的时候(也就是stop最开始调用stopLuck函数的时候),index的值其实是
//比opacity为1的那个盒子下标大1,因为传进来的是:current+1,所以认为下面这种重置opacity的写法会导致错误,但是重点来了!
//这里是设置了一个延时器,并且第一次的延迟时间为time=inTime=0.1s,所以第一次执行stopLuck的时候,opacity为1的那个盒子其实
//已经继续转动一次,所以第一次执行stopLuck函数时候,下面这种写法没有错
if (index > 7) {
index = 0;
divList[7].style.opacity = 0.5;
} else if (index != 0) {
divList[index - 1].style.opacity = 0.5
}
// 当前位置选中状态
divList[index].style.opacity = 1;
// 如果说当前旋转时间太短, 或者当前位置不等于停止位置, 递归一下,直到旋转至停止位置
//(注意:第一次的延迟时间为time=inTime=0.1s)
if (time < 400 || index != luckPosition) {
//思考两个问题?
//第一个问题,如果index == luckPosition的话,会怎么样?
//因为time < 400,仍然也会执行这里,也就是说,即使当前位置等于停止位置也会执行这里,为了是使得速度先变慢。
//然后index会再++直到time>=400并且index==luckPosition不再执行这里。
//第二个问题,为什么越来越慢?
//在最开始的时候,time=100,stepTime=10,index为当前opacity为1盒子的下标,所以执行到这里,递归一下。time值和
//stepTime值变大,那么stopLuck()里面的延时器的延迟时间也会变长,从而使得转圈的速度变慢
//同时index++,延时器里面重置opacity的代码会重置opacity,从而达到转圈的效果
stepTime++;
time += stepTime;
index++;
stopLuck(luckPosition, index, time, stepTime);
} else {
//执行到这里说明当前位置等于停止位置
//设置一个延时器,为了使1s后显示结果
setTimeout(function () {
//这里我们后台手动设置中奖的位置是:1,也就是输入luckPosition的值为1时中奖,当然也可以设置中奖位置为负数,从而永远不中奖
if (luckPosition == 1 ) {
alert("恭喜中奖!")
//恢复按钮
inputStart.disabled=false;
inputStart.value = "抽奖";
animation();
} else {
alert("很遗憾,你没有中奖!")
//恢复按钮
inputStart.disabled=false;
inputStart.value = "抽奖";
animation();
}
},1000)
}
},time)
}
}