页面效果
:页面有6次抽奖机会,每次抽完奖会弹出领奖小弹窗(可选择不要),并在下方的已获列表中展示已获得的奖品列表
第一步,核心js:注释都在代码上
核心代码一:lottery.js
这个lottery.js是核心的js,里面包含了加载页面九宫格相关图片和文字的事件、抽奖事件、抽奖停转事件、奖品领取事件等等。奖品图片、跳转链接、中奖概率皆从后台接口返回的js中取。 暴露了四个方法名用以页面调用。
function lotteryService() {
var lottery = {
index: -1, //当前转动到哪个位置,起点位置
count: 0, //总共有多少个位置
timer: 0, //setTimeout的ID,用clearTimeout清除
speed: 20, //初始转动速度
times: 0, //转动次数
cycle: 50, //转动基本次数:即至少需要转动多少次再进入抽奖环节
prize: -1, //中奖位置
init: function () {
if ($("#lottery-unit").find(".grid-draw-item").length > 0) {
$units = $("#lottery-unit").find(".grid-draw-item");
this.obj = $("#lottery-unit");
this.count = $units.length - 1;
$("#lottery-unit").find(".unit-" + this.index).addClass("grid-draw-item-active");
}
;
},
roll: function () {
var index = this.index;
var count = this.count;
var lottery = this.obj;
$(lottery).find(".unit-" + index).removeClass("grid-draw-item-active");
index += 1;
if (index > count - 1) {
index = 0;
};
$(lottery).find(".unit-" + index).addClass("grid-draw-item-active");
this.index = index;
return false;
},
stop: function (index) {
this.prize = index;
return false;
}
};
/*手机号*/
var mobile = '';
/*抽奖按钮是否可以点击,false 为可以点击*/
var click = false;
/*抽奖总次数*/
var count=6;
/*已抽次数*/
var doneCount=0;
/*所有奖品列表*/
var pricesJosn=[];
/*点击抽奖后滚动的效果*/
function roll() {
lottery.times += 1;
lottery.roll();//转动过程调用的是lottery的roll方法,这里是第一次调用初始化
/*当跑马灯停的时候*/
if (lottery.times > lottery.cycle + 10 && lottery.prize == lottery.index) {
clearTimeout(lottery.timer);
lottery.prize = -1;
lottery.times = 0;
click = false;
var cacheCountLength=0;
/*每次抽奖停下来的时候先从cookie中获取之前的抽奖次数*/
var cacheCount=utilService().getCookie(mobile + "cacheCount");
if(cacheCount!=null&&cacheCount!=undefined){
if(cacheCount==''){
cacheCountLength=0;
}else{
cacheCountLength=cacheCount.split(",").length;
}
/*若之前有抽过奖,那么已抽次数在之前的基础上+1*/
doneCount=cacheCountLength+1;
}else{
doneCount=6;
}
/*总次数-已抽次数=剩余次数 大于零,防止出现抽奖次数为负数的情况*/
if(count-doneCount>=0){
$("#surplusNum").html(count-doneCount);
showPriceDetails(lottery.index);
$('.grid-draw-modal').show()
}
} else {
if (lottery.times < lottery.cycle) {
lottery.speed -= 10;
} else if (lottery.times == lottery.cycle) {
/*根据各奖品概率获取中奖位置*/
apiService().findIndexByRate().then(function (res){
lottery.prize = res;
});
} else {
if (lottery.times > lottery.cycle + 10 && ((lottery.prize == 0 && lottery.index == 7) || lottery.prize == lottery.index + 1)) {
lottery.speed += 110;
} else {
lottery.speed += 20;
}
}
if (lottery.speed < 40) {
lottery.speed = 40;
};
lottery.timer = setTimeout(roll, lottery.speed);//循环调用
}
return false;
}
/*领取奖品*/
function openNewPage(url) {
window.location.href = url;
sessionStorage.setItem(JSON.parse(sessionStorage.formMap).mobile + "-openNewPage", "true");
}
/*加载九宫格小图片*/
function loadLottryImgMini() {
apiService().getLotteryJson().then(function (res){
pricesJosn=res;
});
for(var i=0;i<8;i++){
var priceimgDiv='';
$("#price-imgMini-"+i).html("");
$("#price-imgMini-"+i).append(priceimgDiv);
}
}
/*加载九宫格抽奖停转时弹窗中的图片文字及链接内容*/
function loadLottryImgBig(index) {
if (index == 0) {
$("#price-name").html(pricesJosn[0].title);
$("#price-img").append('');
$("#receiveprice").attr("onclick", "lotteryService().openNewPage('"+pricesJosn[0].link+"')")
} else if (index == 1) {
$("#price-name").html(pricesJosn[1].title);
$("#price-img").append('');
$("#receiveprice").attr("onclick", "lotteryService().openNewPage('"+pricesJosn[1].link+"')")
} else if (index == 2) {
$("#price-name").html(pricesJosn[2].title);
$("#price-img").append('');
$("#receiveprice").attr("onclick", "lotteryService().openNewPage('"+pricesJosn[2].link+"')")
} else if (index == 3) {
$("#price-name").html(pricesJosn[3].title);
$("#price-img").append('');
$("#receiveprice").attr("onclick", "lotteryService().openNewPage('"+pricesJosn[3].link+"')")
} else if (index == 4) {
$("#price-name").html(pricesJosn[4].title);
$("#price-img").append('');
$("#receiveprice").attr("onclick", "lotteryService().openNewPage('"+pricesJosn[4].link+"')")
} else if (index == 5) {
$("#price-name").html(pricesJosn[5].title);
$("#price-img").append('');
$("#receiveprice").attr("onclick", "lotteryService().openNewPage('"+pricesJosn[5].link+"')")
} else if (index == 6) {
$("#price-name").html(pricesJosn[6].title);
$("#price-img").append('');
$("#receiveprice").attr("onclick", "lotteryService().openNewPage('"+pricesJosn[6].link+"')")
} else if (index == 7) {
$("#price-name").html(pricesJosn[7].title);
$("#price-img").append('');
$("#receiveprice").attr("onclick", "lotteryService().openNewPage('"+pricesJosn[7].link+"')")
}
}
/*加载所有奖品*/
function loadPrizeItems() {
for(var i=0;i<8;i++){
var priceItemDiv='';
$("#itemunit-"+i).html("");
$("#itemunit-"+i).append(priceItemDiv);
}
}
/*加载已获奖品*/
function showPrizeItems(mobile) {
var cacheCountArray=[];
var cacheCount = utilService().getCookie(mobile + "cacheCount");
if(cacheCount != ""&& cacheCount != undefined){
$("#prize-show").show();
cacheCountArray=cacheCount.split(",");
var notUniqueArr=cacheCountArray;
cacheCountArray=utilService().ListUnique(cacheCountArray);
$("#scroll-box").html("");
for(var i=0;i' +
'' +
'
核心代码二:util.js
这个util.js主要包含了cookie的设置和获取,以及数组的去重这三个方法,并返回相应接口。cookie设置和获取的时候有经过前端window对象基本加密,此处还可以设置js高级加密,比较简单不赘述。
function utilService() {
var setCookie = function (cname, cvalue, exdays){
cvalue=window.btoa(cvalue);
var d = new Date();
d.setTime(d.getTime() + (exdays*24*60*60*1000));
var expires = "expires="+ d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
};
var getCookie=function(cname){
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for(var i = 0; i
核心代码三:apiService.js
这个js主要包含了以下三个方法,涉及隐私就不放出来了
用于访问后台接口并获取到返回值,同时后台也应有3个相应接口。
getLotteryJson,(获取到抽奖配置信息:包含奖品位置,奖品大图,奖品小图,奖品标题,奖品跳转链接)
findIndexByRate,(根据后台设置的中奖概率设置中奖位置)
recordLotteryLog,(每次抽奖记录一下抽奖结果,没有返回值,仅做记录之用)
第二步:核心css,样式中xxx.com是图片的链接
@charset "utf-8";
/* CSS Document */
html, body, div, span,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
img, ins, kbd, q, s, samp,
small, strike, strong,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,input{
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-size: 13px;
font-family: '微软雅黑';
}
ol, ul {list-style: none;}
a{text-decoration: none;}
i{font-style:normal;}
li{list-style:none;}
input[type='submit'],input[type='button'],input[type='text'],input[type='tel'],input[type='date'],img,label{-webkit-appearance:none;-webkit-tap-highlight-color:rgba(255,255,255,0);}
img{display: block;}
select{background-color:transparent;
border-color:transparent;
-webkit-appearance: none; }
.result-grid-draw-fyl-comp {
width: 94%;
height: 178px;
background-image: url(https://xxx.com/activities/images/lottery/doLotto_div.png);
background-size: 100% 100%;
-webkit-box-sizing: border-box;
box-sizing: border-box;
padding: 12px 20px;
margin-top: 30px;
margin-left: 3%;
}
.result-grid-draw-fyl-comp section {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-webkit-justify-content: space-between;
-ms-flex-pack: justify;
justify-content: space-between;
margin-bottom: 6px;
}
.result-grid-draw-fyl-comp section .grid-draw-item {
width: 95px;
height: 48px;
background-image: url(https://xxx.com/activities/images/lottery/squared-defult.svg);
background-size: 100% 100%;
border-radius: 12px;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.result-grid-draw-fyl-comp section .grid-draw-item .price-img {
width: 100%;
height: 100%;
margin: 0 auto;
}
.result-grid-draw-fyl-comp section .grid-draw-item .price-img img {
width: 100%;
height: 100%;
display: block;
margin: 0 auto;
}
.result-grid-draw-fyl-comp section .draw-button {
background: #f67b0d;
border-radius: 12px;
position: relative;
}
.result-grid-draw-fyl-comp section .draw-button .btn {
height: 40px;
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(17%, #ffda59), to(#ffb703));
background-image: linear-gradient(180deg, #ffda59 17%, #ffb703);
border-radius: 12px;
font-family: PingFangSC-Semibold;
line-height: 24px;
font-size: 16px;
color: #e90000;
letter-spacing: 0;
text-align: center;
}
.result-grid-draw-fyl-comp section .draw-button .tips {
font-size: 10px;
color: #e90000;
letter-spacing: 0;
text-align: center;
line-height: 14px;
position: absolute;
width: 100%;
bottom: 10px;
}
.result-grid-draw-fyl-comp section .draw-button .tips span {
font-size: 14px;
color: #fff;
}
.result-grid-draw-page main .prize-show .title {
width: 20%;
height: 22px;
margin: 16px auto 12px;
margin-left: 40%;
}
.result-grid-draw-page main .prize-show .title img {
width: 100%;
display: block;
}
.result-grid-draw-page main .prize-show .prize-box {
width: 345px;
height: 80px;
margin: 0 auto;
background-image: url(https://xxx.com/activities/images/lottery/doLotto_myprize_contentbg.png);
background-size: 100% 100%;
-webkit-box-sizing: border-box;
box-sizing: border-box;
position: relative;
}
.result-grid-draw-page main .prize-show .prize-box .left {
width: 34px;
height: 80px;
position: absolute;
top: 0;
left: 0;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
-webkit-justify-content: space-around;
justify-content: space-around;
-webkit-tap-highlight-color: transparent;
}
.result-grid-draw-page main .prize-show .prize-box .prize-items {
height: 80px;
overflow-x: auto;
overflow-y: hidden;
max-width: 280px;
position: absolute;
top: 0;
left: 34px;
}
.result-grid-draw-page main .prize-show .prize-box .right {
width: 34px;
height: 80px;
position: absolute;
top: 0;
right: 0;
z-index: 3;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
-webkit-justify-content: space-around;
justify-content: space-around;
-webkit-tap-highlight-color: transparent;
}
.result-grid-draw-page main .prize-show .prize-box .left .switch {
width: 7.5px;
height: 13.5px;
background-image: url(https://xxx.com/activities/images/lottery/nextprize.png);
background-size: 100% 100%;
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
.result-grid-draw-page main .prize-show .prize-box .prize-items .scroll-box {
padding: 15px 0;
-webkit-transition: all .3s linear;
transition: all .3s linear;
}
.result-grid-draw-page main .prize-show .prize-box .prize-items .scroll-box .item {
width: 66px;
height: 48px;
margin-right: 4px;
display: inline-block;
}
.result-grid-draw-page main .prize-show .prize-box .prize-items .scroll-box .item img {
width: 100%;
height: 100%;
}
.result-grid-draw-fyl-comp section .grid-draw-item-active {
background-image: url(https://xxx.com/activities/images/lottery/squared-select.svg);
}
.result-grid-draw-page main .prize-show .prize-box .right {
width: 34px;
height: 80px;
position: absolute;
top: 0;
right: 0;
z-index: 3;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
-webkit-justify-content: space-around;
justify-content: space-around;
-webkit-tap-highlight-color: transparent;
}
.result-grid-draw-page main .prize-show .prize-box .right .switch {
width: 7.5px;
height: 13.5px;
background-image: url(https://xxx.com/activities/images/lottery/nextprize.png);
background-size: 100% 100%;
}
.grid-draw-modal {
width: 100%;
height: 100vh;
background: rgba(0, 0, 0, .6);
position: fixed;
top: 0;
left: 0;
}
.grid-draw-modal .modal {
width: 325px;
height: 415px;
position: relative;
top: 50px;
left: 50%;
margin-left: -162.5px;
background-image: url(https://xxx.com/activities/images/lottery/doLotto_bg.png);
background-size: 100% 100%;
}
.grid-draw-modal .modal .price-details {
position: absolute;
top: 136px;
left: 0;
width: 100%;
}
.grid-draw-modal .modal .price-details .price-name {
font-size: 16px;
color: #fff;
text-align: center;
margin-top: 10px;
}
.grid-draw-modal .modal .price-details .price-img {
width: 270px;
height: 130px;
margin: 15px auto 0;
}
.grid-draw-modal .modal .price-details .price-img img {
width: 100%;
height: 100%;
}
.grid-draw-modal .modal .modal-footer {
width: 100%;
height: 125px;
background-image: url(https://xxx.com/activities/images/lottery/Completion%20page_bg2.png);
background-size: 100% 100%;
position: absolute;
bottom: 0;
left: 0;
}
.grid-draw-modal .modal .modal-footer .receive {
width: 234px;
height: 44px;
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(17%, #ffd559), to(#ffb503));
background-image: linear-gradient(180deg, #ffd559 17%, #ffb503);
border-radius: 22px;
margin: 46px auto 0;
text-align: center;
line-height: 44px;
font-size: 18px;
color: #e90000;
}
.grid-draw-modal .modal .close {
width: 32px;
height: 32px;
background-image: url(https://xxx.com/activities/images/lottery/icon_close.png);
background-size: 100% 100%;
position: absolute;
bottom: -56px;
left: 50%;
margin-left: -16px;
}
.scroll-box .showitem {
display: inline;
}
.result-content{
background-image: url(https://xxx.com/activities/images/collection_20191010/success_top2.png);
background-size: contain;
text-align: center;
font-family: PingFangSC-Regular;
letter-spacing: 0;
color: #081d43;
padding: 7px 0 22px;
}
.offer-title {
width: 108px;
height: 25px;
margin: 22px auto 0;
background-image: url(https://xxx.com/activities/images/collection_20191010/offer_title.png);
background-size: 100%;
background-repeat: no-repeat;
}
.offer-box .offer-list {
margin: 0 20px;
overflow: hidden;
}
.offer-box .offer-list>a {
float: left;
width: calc(50% - 10px);
height: auto;
margin-top: 15px;
}
.offer-box .offer-list>a:nth-child(2n) {
float: right;
}
.company{
font-family: PingFangSC-Medium;
font-size: 15px;
color: #ff491b;
}
第三步:核心html片段
第四步,前端这样就差不多了
下面来看后端
后端就比较简单,新建两个实体,
一个用来存奖品配置信息,并在接口中将配置信息用json返回给前端,
一个用来存中奖信息记录,当然没有这个业务需要的话也可以不存。
后端稍微需要注意的有两点,
一个是中奖概率的算法,由于本人算法不行,所以借鉴的网上的案例:根据每个位置的所设的中奖概率返回一个中奖位置。如果有更好的实现也欢迎在下面评论留言
代码如下:
/**
* Math.random()产生一个double型的随机数,判断一下
* 例如0出现的概率为%50,则介于0到0.50中间的返回0
*
* @return int
*/
private int percentageRandom(Map rateMap) {
double rate0=Double.parseDouble(rateMap.get("rate0").toString());
double rate1=Double.parseDouble(rateMap.get("rate1").toString());
double rate2=Double.parseDouble(rateMap.get("rate2").toString());
double rate3=Double.parseDouble(rateMap.get("rate3").toString());
double rate4=Double.parseDouble(rateMap.get("rate4").toString());
double rate5=Double.parseDouble(rateMap.get("rate5").toString());
double rate6=Double.parseDouble(rateMap.get("rate6").toString());
double rate7=Double.parseDouble(rateMap.get("rate7").toString());
double randomNumber = Math.random();
if (randomNumber >= 0 && randomNumber <= rate0) {
return 0;
} else if (randomNumber > rate0 && randomNumber <= rate0 + rate1) {
return 1;
} else if (randomNumber >= rate0 + rate1
&& randomNumber <= rate0 + rate1 + rate2) {
return 2;
} else if (randomNumber >= rate0 + rate1 + rate2
&& randomNumber <= rate0 + rate1 + rate2 + rate3) {
return 3;
} else if (randomNumber >= rate0 + rate1 + rate2 + rate3
&& randomNumber <= rate0 + rate1 + rate2 + rate3 + rate4) {
return 4;
} else if (randomNumber >= rate0 + rate1 + rate2 + rate3 + rate4
&& randomNumber <= rate0 + rate1 + rate2 + rate3 + rate4+ rate5) {
return 5;
} else if (randomNumber >= rate0 + rate1 + rate2 + rate3 + rate4 + rate5
&& randomNumber <= rate0 + rate1 + rate2 + rate3 + rate4 + rate5 + rate6) {
return 6;
} else if (randomNumber >= rate0 + rate1 + rate2 + rate3 + rate4 + rate5 + rate6
&& randomNumber <= rate0 + rate1 + rate2 + rate3 + rate4 + rate5 + rate6 + rate7) {
return 7;
}
return -1;
}
第二个需要注意的是一个小优化,
由于奖品配置信息及概率都存在数据库中,每次用户点击抽奖都去访问一遍数据库的话,服务器的压力可能会有点大,所以建议用@PostConstruct注解注释在取数据库信息的方法上,这样这个方法只会执行一次,减少了数据库的压力。
还有很多不足的,我在积极更正,欢迎指教
编写不易,转载注出