《jQuery》实现一个H5的九宫格抽奖

func(jQuery,plugin)

})(this,function(jQuery,plugin){

const defaultName = ‘谢谢惠顾’;

//奖品列表上限数量8

const maxListNumber = 8;

const puginID = ‘oliverPrizeDraw’;

const row = 3;

const column = 3;

let flg=false;

let this;

$.fn[plugin] = function(params) {

let _this = this;

if(!isObj(params)) throwError(‘传入的参数必须是一个对象’);

//此时的createDOMList仅仅是一个数组,尚未插入DOM树中

let createDOMList = createDomListArr(params.prizeList);

//在createDOM()函数中创建DOM,并返回了中间“开始”按钮的ID,这样方便给按钮添加点击事件

let btn = createDOM(createDOMList,_this);

}

//根据参数,按顺序创建了9个div,保存在了数组中返回

function createDomListArr(arr){

let newArr = [];

arr.forEach((el,index) => {

newArr.push(<div data-id='${el.id}' index='${index}'>${el.name}</div>)

})

return newArr;

}

//创建DOM

function createDOM(list,dom){

//创建了一个div,作为外框的父级元素

let divContainer = <div id='${puginID+'Container'}'></div>;

//将外框加入页面上

dom.append(divContainer);

//创建一个div用来存放8个抽奖元素

let div = <div id='${puginID+'Box'}'></div>;

//将用来存放抽奖元素的div加入外框下

$(‘#’+puginID+‘Container’).append(div);

//获得到上面刚刚加入到页面上用来存放抽奖元素的box

let box = $(‘#’+puginID+‘Box’);

//将上面生成的8个抽奖元素统统放进去,此时里面的抽奖元素还没有最终排列成需要的形态

box.append(list);

//获得8个抽奖元素

let children = box.children();

//对每个抽奖元素的大小进行设定,每个方块的大小都设定成父元素的三分之一

//里面的-4是因为需要做间隔

children.css({

‘width’:box.width()/row-4+‘px’,

‘height’:box.height()/column-4+‘px’,

‘line-height’:box.height()/column-4+‘px’,

})

}

//是否是个对象

function isObj(obj){

return Object.prototype.toString.call(obj) === ‘[object Object]’;

}

},‘prizeDraw’)

当执行到这里的时候,已经创建好了8个div,并且每个div的大小都已经设置成外框的三分之一大小了(其他具体的样式,比如间隔,背景色等等都是通过css设置的);

开始按钮和排列位置

当时的基本思路是,一个父级元素div作为外框,下面有两部分:

  • 第一部分是中间的开始按钮;

  • 第二部分是一个div,这个div下有按钮周围一圈的奖品;

这两部分一共9格,采用的都是绝对定位,只有绝对定位可以按照意愿随意摆放位置;

//创建DOM

function createDOM(list,dom){

/*

第一小节代码放这里

*/

//-----------------分割线--------------//

//对8个元素每个都执行一次位置排放

children.each((index,el)=>{

//第0-1个,也就是第1、第2个方块

//离顶部的距离是0,每一个方块相对前面一个方块离左侧的距离是多一个方块的宽度

if(index >= 0 && index < (row-1)){

$(el).css({

‘top’:0,

‘left’:index*(box.width()/row)+‘px’

})

}

//第3,第4个方块,离右侧的距离是0,离顶部是逐一多一个方块的距离

//

else if(index>=row-1 && index<row+column-1){

$(el).css({

‘right’:0,

‘top’:(index-2)*(box.height()/column)+‘px’

})

}

//第5,第6个方法,离底部的距离是0,离右侧的距离逐一多一个方块的距离

else if(index>=row-1+column&&index<(2*row+column-2)){

$(el).css({

‘bottom’:0,

‘right’:(index-(row+column-2))*(box.width()/row)+‘px’

})

}

//第7,第8个,离左侧的距离是0,距离顶部的距离是处于第二排,第三排

else{

$(el).css({

‘top’:(index-(2*(row+column)-6))*(box.height()/column)+‘px’,

‘left’:0

})

}

})

//创建开始按钮

let startBtn = <span id='${puginID+'StartBtn'}' class='start-btn start-btn-able'>开始</span>;

//将按钮加入DOM

box.parent().append(startBtn);

给按钮设置样式,将其置于正中间

$(‘#’+puginID+‘StartBtn’).css({

‘width’:box.width()/row-4+‘px’,

‘height’:box.height()/column-4+‘px’,

‘line-height’:box.height()/column-4+‘px’,

‘left’:box.width()/row+‘px’,

‘top’:box.height()/column+‘px’,

// ‘transform’:‘translate(-50%,-50%)’

})

//返回按钮

return {

startBtn:puginID+‘StartBtn’,

boxId:puginID+‘Box’

}

}

筛选奖品和启动转动动画


在这个阶段,需要给开始按钮绑定点击事件,点击后可以启动转动动画,当然在启动之前,必须对奖品数组进行一系列检测,如果有错误进行简单的处理,最终返回一个我们需要的抽奖数组,这个最终的抽奖数组才上面插入DOM的div,也就是说,实际上对传入的参数进行检测这一步应该放在排列位置之前

有了最终的合法的抽奖数组,那么就可以根据需求,筛选最终奖品;

检测参数

$.fn[plugin] = function(params) {

let _this = this;

if(!isObj(params)) throwError(‘传入的参数必须是一个对象’);

//再创建之前,需要先对传入的参数做一次检测,如果参数错误,长度错误可以及时补齐或抛出异常

params.prizeList = finalList(params.prizeList);

//此时的createDOMList仅仅是一个数组,尚未插入DOM树中

let createDOMList = createDomListArr(params.prizeList);

let btn = createDOM(createDOMList,_this);

}

//检测参数

function finalList(arr){

//存在且必须是数组

if(!(arr && Array.isArray(arr))){

let newArr = [];

for(let i = 0 ; i < maxListNumber ; i++){

//数组每一项都有名字,id和概率

newArr.push({

name:defaultName,

id:puginID + i,

percent:100 / maxListNumber

});

}

//返回数组

return newArr;

}

//概率这一项必须是数字

arr.forEach((el)=>{

if(!isNumber(el.percent)){

throwError(‘奖品列表的percent的值必须是数字类型,当前ID为:’+el.id+’ 的percent值不是数字’);

}

})

//奖品列表长度必须是8

if(arr.length === maxListNumber){

//概率的总和必须是100,不能8个方块的概率加起来超出100了

let percent = resultPro(arr);

if(percent !== 100) throwError(‘奖品列表的概率和必须是100,当前是:’+percent);

return arr;

}

else{

//假如传入的参数的长度超过了8,提示

let length = maxListNumber - arr.length;

length = length > 0 ? length : throwError(‘奖品列表的数量上限是:’+maxListNumber+‘,当前是:’+arr.length);

//当前概率和

let current = resultPro(arr);

if(current>100) throwError(‘奖品列表的概率和必须小于100,当前是:’+current);

for(let i = 0 ; i < length ; i++){

arr.push({

name:defaultName,

id:puginID + i,

percent:(100 - current) / length

})

}

//返回打乱的数组,不能是输入的奖品顺序是什么就是什么

return arr.sort(randomArr);

}

}

//判断当前的奖品列表的概率总计

function resultPro(arr){

if(!Array.isArray(arr)) throwError(‘resultPro的参数必须是数组’);

let result = 0;

arr.forEach((el) => {

el.percent && isNumber(el.percent)? result = result + el.percent : ‘’;

})

return result;

}

//打乱数组

function randomArr(a,b){

return Math.random()>.5 ? -1 : 1;

}

//抛出异常

function throwError(val){

throw new Error(val)

}

等检测完,此时返回的抽奖数组就是一个完整的奖品数组了,在第一步创建div的时候就可以按照这个顺序直接创建div并排列;

点击开始按钮

到这一阶段,就需要给开始按钮添加点击事件了,并且点击后开始按钮进入disable的状态,不然连续点击就会出现问题,并且,点击“开始”按钮后,会出现两种情况:

  • 存在指定奖品,也就是俗称的黑幕,不管谁抽,都是谢谢惠顾之类的;

  • 不存在指定奖品,那么就会按照设定的概率进行抽奖;

$.fn[plugin] = function(params) {

let _this = this;

if(!isObj(params)) throwError(‘传入的参数必须是一个对象’);

//生成抽奖数组

params.prizeList = finalList(params.prizeList);

let createDOMList = createDomListArr(params.prizeList);

//创建DOM并返回按钮ID

let btn = createDOM(createDOMList,_this);

let boxChinldren = btn.boxId;

$(‘#’+btn.startBtn).on(‘click’,function(){

this = this;

//通过flg开关,判断是否可以点击

if(!flg){

//添加不可点击时的样式;

$(this).addClass(‘start-btn-disable’).removeClass(‘start-btn-able’);

flg = true;

//判断是否有指定奖品ID

//假如有指定奖品,那么概率抽奖就不会生效,假如没有,那么就进行概率抽奖

if(params.finalPrizeID&&isString(params.finalPrizeID)){

//判断一下设定的最终奖品id存不存在

//不要设定了一个奖品id,结果奖品列表中没有,或者有2个及2个以上的奖品

let array = [];

params.prizeList.forEach(element => {

if(element.id === params.finalPrizeID){

array.push(element);

}

})

//根据数组长度进行判断

switch(array.length){

//长度是0,那么就说明指定的id不存在,那么将进行概率抽奖

case 0:

console.log(‘指定的奖品ID在奖品列表中不存在,将按指定概率进行抽奖’);

//这个是抽奖函数,下一大节解释这个函数

targetPrize(params.prizeList,boxChinldren);

break

//长度是1,那么这个就是正常情况,这个奖品就是最终奖品

case 1:

let name = array[0].name?array[0].name:‘默认名字’;

console.log(‘指定奖品为:’+name);

targetPrize(array[0],boxChinldren);

break

//长度超出了1个,那么就是存在多个相同id的最终奖品,其实也可以进行概率抽奖

default:

throwError(‘指定的最终奖品ID在奖品列表中不唯一’);

break;

}

}

//没有指定奖品,那么就正常进行概率抽奖

else{

console.log(‘无指定奖品,将按指定概率进行抽奖’);

targetPrize(params.prizeList,boxChinldren);

}

}

})

}

抽奖函数


在上一大节中,通过targetPrize函数,进行抽奖,其中第一个参数:

  • 如果是一个对象,那么就代表直接传递过来了最终奖品,那么就不需要通过函数去计算哪个是最终奖品;

  • 如果是一个数组,那么代表使用者并没有设定最终奖品,需要按照概率进行随机抽取;

其中,如果是数组,大致上就是将数组中的每一项奖品的概率转成一个区间,比如:第一个奖品的概率是10,那么在100中,随机数0-9指的就是这个奖品,如果第二个奖品的该也是10,那么转换后10-19就是这个奖品,第三个奖品的概率是30,那么它所对应的区间就是20-59,以此类推;

这样就将奖品的概率平铺满了100,到这里的抽奖只需要随机数一个0-100的数字,这个数字在哪个区间,就代表抽中了哪个奖品;

//执行抽奖,传入的正常抽奖或者是指定奖品,dom列表

function targetPrize(params,dom){

//如果是对象,执行指定奖品,如果是数组,执行概率抽奖

isObj(params)?

pointPrize(params,dom):

Array.isArray(params)?

percentPrize(params,dom):

throwError(‘targetPrize()参数错误’);

}

//指定奖品

function pointPrize(params,dom){

//指定产品的位置

let ax = targetIndex(params,dom)

console.log(params);

speedUp(dom,ax);

}

//概率抽奖

function percentPrize(params,dom){

//将概率转成数组区间

let newArr = arrayPercent(params);

//获得最终奖品

let percent = objPercent(newArr);

console.log(percent);

//指定产品的位置

let ax = targetIndex(percent,dom)

speedUp(dom,ax);

}

//将概率转成区间数组

function arrayPercent(arr){

let sum = 0;

let newArr=[];

arr.forEach((el)=>{

el.percent&&isNumber(el.percent)?

newArr.push({

name:el.name,

id:el.id,

percent:[sum,(sum+el.percent)===100?(sum=sum+el.percent):(sum=sum+el.percent)-1]

}):‘’;

})

return newArr;

}

//选出一个随机数并返回指定区间的对象

function objPercent(arr){

let radomNum = Math.floor(Math.random() * 100);

console.log(radomNum);

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

//选出一个随机数并返回指定区间的对象

function objPercent(arr){

let radomNum = Math.floor(Math.random() * 100);

console.log(radomNum);

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-Apxjoei1-1715720408871)]

[外链图片转存中…(img-3AOyolJ6-1715720408871)]

[外链图片转存中…(img-FUkOOC32-1715720408872)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点!不论你是刚入门Android开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值