封装小程序抽奖组件
封装小程序抽奖组件组件页面代码luckDraw.wxml组件样式表luckDraw.wxss组件逻辑脚本 luckDraw.js使用页面 index.wxml使用页面逻辑脚本 index.js效果希望和各位前端大神一起学习【QQ:1787750205】最近项目有一个需求,实现一个抽奖功能,于是封装了一个抽奖组件,可以配置奖项权重(中奖比例)或指定抽中某一个固定奖项。组件页面代码luckDraw.w
·
封装小程序抽奖组件
希望和各位前端大神一起学习【QQ:1787750205】
最近项目有一个需求,实现一个抽奖功能,于是封装了一个抽奖组件,
可以配置奖项权重(中奖比例)或指定抽中某一个固定奖项。
组件页面代码luckDraw.wxml
<view class="body" style="width:{{bodyWidth}};margin-left:calc((100vw - {{bodyWidth}}) / 2);">
<!-- 奖项列表 -->
<view class="itemBody">
<!-- 奖项 -->
<view class="item"
style="width:calc((100% - 8rpx * {{size * 2}}) / {{size}});height:{{itemHeight?itemHeight+'rpx': 'calc(('+bodyWidth+' - 8rpx * '+size * 2+') / '+size+')'}};"
wx:for="{{allList}}" wx:key="index">
<!-- 当前奖项抽中时的遮罩 -->
<view wx:if="{{item.isChoose}}"
class="showItem"
style="background-color:{{chooseColor}}"></view>
<!-- 奖项图片 -->
<image class="bgPic" wx:if="{{item.info.pic}}" src="{{item.info.pic}}" />
<!-- 奖项标题 -->
<view class="itemTitle">{{item.info.title}}</view>
<!-- 奖项副标题 -->
<view class="itemSubTitle">{{item.info.subTitle}}</view>
</view>
</view>
<!-- 开始抽奖按钮 -->
<view class="startBtn"
style="width:calc({{bodyWidth}} / 3 - 16rpx);height:calc({{bodyWidth}} / 3 - 16rpx);margin-left:calc(({{bodyWidth}} - ({{bodyWidth}} / 3 - 16rpx)) / 2);top:calc(({{bodyWidth}} - ({{bodyWidth}} / 3 - 16rpx)) / 2);background-color:{{startBtn.bgColor?startBtn.bgColor:'#FEE300'}};border-radius:{{startBtn.radius?startBtn.radius:10}}rpx;"
bindtap="setRes">
<!-- 按钮文字 -->
<view style="color:{{startBtn.color?startBtn.color:'#F6251D'}}">{{startBtn.text?startBtn.text:'开始抽奖'}}</view>
<!-- 按钮副标题 -->
<text style="color:{{startBtn.subColor?startBtn.subColor:'#FB6761'}}">{{startBtn.subTitle?startBtn.subTitle:''}}</text>
</view>
</view>
组件样式表luckDraw.wxss
.body{
width: 99.5vw;position: relative;
}
.itemBody{
width: 100%;position: relative;display: flex;flex-wrap: wrap;justify-content: center;
}
.item{
position: relative;margin: 6rpx;display: flex;flex-direction: column;align-items: center;justify-content: center;
}
.showItem{
position: absolute;z-index: 30;width: 100%;height: 100%;opacity: 0.5;border: 1rpx solid;
}
.bgPic{
position: absolute;width: 100%;height: 100%;z-index: 1;
}
.itemTitle{
position: relative;font-size: 30rpx;font-weight: bold;z-index: 10;text-align: center;padding: 0 10rpx;
}
.itemSubTitle{
position: relative;font-size: 24rpx;margin-top: 10rpx;z-index: 10;text-align: center;padding: 0 10rpx;
}
.startBtn{
position: absolute;z-index: 20;display: flex;flex-direction: column;align-items: center;justify-content: center;font-weight: bold;font-size: 40rpx;
}
.startBtn text{
display: block;font-weight: normal;font-size: 28rpx;margin-top: 10rpx;
}
组件逻辑脚本 luckDraw.js
let _this
let chooseIndex = 0//当前选中的奖项
let relSize//有效奖项个数
let size//规格
let indexList = []//存放奖项下标映射
let isRonate = false//是否正处于抽奖状态
// 私有函数使用‘_’号开头命名,仅作为本功能工具函数使用
Component({
properties: {
size: {//设置size*size的宫格
//实际有效奖项个数:3*3-8 4*4-12 5*5-16 6*6-20,总结规律:(size - 1) * 4
type: Number,
value: 3//默认为3*3的九宫格,可以自定义4*4的16宫格或者更多,但是建议最多5个
},
list: {//奖项列表
type: Array,
value: []
/**
* weight:权重(概率),如果没传则默认视为概率都是一样的
* title:奖项名称【必填】
* subTitle:奖项副标题
* pic:奖项图片
* 其他自定义属性(结果回调时根据业务进行不同的事件处理)
*/
},
bodyWidth: {//整体宽度
type: String,
value: '100vw'
},
itemHeight: {//子项高度 默认和宽度一致
type: Number,
value: 0
},
chooseColor: {//选中时的遮罩颜色
type: String,
value: '#000'
},
startBtn: {
type: Object,
value: {
/**
* bgColor:抽奖按钮背景色
* color:抽奖按钮主体文字颜色
* subColor:抽奖按钮副标题文字颜色
* radius:抽奖按钮圆角
* text:抽奖按钮主体文字
* subTitle:抽奖按钮副标题文字
*/
}
}
},
data: {
allList: []
},
methods: {
//初始化数据处理
render: function(){
let list = this.data.list
//自动生成跟weight权重(比例)配合使用的奖项id
list.forEach((item,index)=>{
item['id'] = index
if (!item.weight) {//如果没传权重则默认视为概率为 1/权重总数
item['weight'] = 1
}
});
this.setData({
list
},()=>{
size = this.data.size
relSize = (size - 1) * 4
let allList = []
// 分别设置上右下左最开始取的下标
let renderT = 0,
renderR = size - 1,
renderB = size * 3 - 2 - 1,
renderL = size * 3 - 2 + (size - 3);
//创建抽奖转盘列表
for (let i = 0; i < size * size; i++) {
allList.push({index: i})
}
//判断哪些是真实有效的列表项
allList.forEach((item,index) => {
item.isChoose = false
let isRelItem = index + 1 < size + 2 || index + 1 > (size * size - size - 1) || (index + 1) % size == 1 || (index + 1) % size == 0
item.isRelItem = isRelItem
//第二行开始顺时针取边上的
let nowL = index + 1
if (nowL > size) {
// console.log(`${nowL}%${size}=${nowL%size}`)
//先取右边除第一行外的最后一个
if (nowL % size == 0) {
item.relIndex = renderR + 1
item.info = list[renderR + 1]
renderR += 1
}
//再取下边除最后一个的其他
if (nowL > (size * (size - 1)) && nowL < size * size){
//需要反向设置
item.relIndex = renderB
item.info = list[renderB]
renderB -= 1
}
//取左边除第一个和最后一个的其他
if (nowL % size == 1 && nowL != size * (size - 1) + 1) {
item.relIndex = renderL
item.info = list[renderL]
renderL -= 1
}
}else{
item.relIndex = renderT
item.info = list[renderT]
renderT += 1
}
//将奖品信息装入有效的抽奖项
if(isRelItem){
item.info = list[item.relIndex]
}
})
this.setData({allList},()=>{
let findItem
indexList = []
for (let i = 0; i < relSize; i++) {
findItem = allList.find(item => item.relIndex == i)
indexList.push(findItem.index)
}
})
});
},
//设置结果并通过triggerEvent回调给父组件,默认为基于权重生成随机数,如果指定了awards则固定获得第awards+1个奖项
setRes: function(e,awards){
//参数e仅是为了忽略内部参数,勿删
//如果正在抽奖则不可重复抽奖,需要等上一次抽奖完成
if (isRonate) return;
if (!awards) {
awards = this._weightRandom();
}else{
awards = Number(awards)
}
console.log(awards)
this._ronate(awards,2,res=>{
_this.triggerEvent('luckdraw', {luckdraw: res}, {})
})
},
//【私有函数】基于权重生成随机数,可指定值
_weightRandom: function(awards){
let randomConfig = this.data.list;
let randomList = [];
for (let i in randomConfig) {
for (let j = 0; j < randomConfig[i].weight; j++) {
randomList.push(randomConfig[i].id);
}
}
let randomValue = randomList[Math.floor(Math.random() * randomList.length)];
//一直生成,直到生成希望的为止
// if (awards != 0) {
// while (randomValue == curVal ) {
// randomValue = randomList[Math.floor(Math.random() * randomList.length)];
// }
// }
return randomValue;
},
//【私有函数】抽奖转动(最终停留奖项的下标,转圈次数,回调函数)
_ronate: function(jumpNum,quanNum,result){
let jumpnum = 0
isRonate = true
_this.setData({
['allList[0].isChoose']:true
})
//若不是第一次抽奖,上一次抽中的奖项重置
if (chooseIndex != 0) {
_this.setData({
['allList['+indexList[chooseIndex]+'].isChoose']:false
},()=>{
chooseIndex = 0
})
}
//基准延时速度
let step = 150;
let myFunction = function(){
clearInterval(timer);
_this.setData({
['allList['+indexList[chooseIndex]+'].isChoose']:false
})
chooseIndex ++
jumpnum ++
if (size == 3) {
if (jumpNum < relSize / 2) {
step = step + jumpnum * 2
}else{
step = step + jumpnum
}
} else if(size == 4) {
if (jumpNum < relSize / 2) {
step = step + jumpnum
}else{
step = step + jumpnum * 0.5
}
}else{
if (jumpNum < relSize / 2) {
step = step + jumpnum * 0.5
}else{
step = step + jumpnum * 0.25
}
}
if (chooseIndex == relSize) {
chooseIndex = 0
}
_this.setData({
['allList['+indexList[chooseIndex]+'].isChoose']:true
})
if (jumpnum == jumpNum + (quanNum * relSize)) {
clearInterval(timer)
isRonate = false
let resItem = _this.data.allList[indexList[chooseIndex]]
result(resItem)
}else{
timer = setInterval(myFunction, step);
}
}
let timer = setInterval(myFunction, step);
}
},
attached: function(){
_this = this
this.render();
}
})
使用页面 index.wxml
<!-- 使用抽奖组件-默认为依据奖项权重随机抽奖 -->
<luck-draw size="{{4}}"
list="{{list}}"
startBtn="{{startBtn}}"
id="luckDraw"
bind:luckdraw="luckdraw"></luck-draw>
<!-- 固定抽到奖项“谢谢参与”(data-num设置指定奖项的下标) -->
<view bindtap="go" data-num="11" style="margin-top:100rpx">
指定抽中固定奖项
</view>
使用页面逻辑脚本 index.js
let _this
let luckDrawBtn;
Page({
data: {
list: [//奖励列表 weight权重(中奖比例)
{title: '特等奖',subTitle: '苏州全款4室1厅住宅*1',pic: './timg.jpg',weight:1},
{title: '一等奖',subTitle: '全款五菱神车*1',pic: './timg.jpg',weight:2},
{title: '二等奖',subTitle: '全年帮还花呗',pic: './timg.jpg',weight:3},
{title: '三等奖',subTitle: '现金8888元',pic: './timg.jpg',weight:4},
{title: '四等奖',subTitle: '现金888元',pic: './timg.jpg',weight:5},
{title: '五等奖',subTitle: '现金88元',pic: './timg.jpg',weight:6},
{title: '六等奖',subTitle: '现金8元',pic: './timg.jpg',weight:7},
{title: '幸运奖',subTitle: '通用优惠券1000元',pic: './timg.jpg',weight:8},
{title: '支持奖',subTitle: '通用优惠券100元',pic: './timg.jpg',weight:13},
{title: '鼓励奖',subTitle: '通用优惠券10元',pic: './timg.jpg',weight:25},
{title: '安慰奖',subTitle: '通用优惠券1元',pic: './timg.jpg',weight:50},
{title: '谢谢参与',subTitle: '',pic: './timg.jpg',weight:100,type:'未中奖'}
],
startBtn: {
text: '随机抽奖',
subTitle: '100葫芦/次'
}
},
onLoad: function(){
_this = this
},
onReady: function(){
luckDrawBtn = _this.selectComponent("#luckDraw");
},
//指定抽某一个奖项
go: function(e){
luckDrawBtn.setRes(null,e.currentTarget.dataset.num)
},
//抽奖组件回调
luckdraw: function(e){
// 回调中可以根据业务进行相应时间处理,例如抽奖次数-1或积分-1或对抽中奖项进行判断
let item = e.detail.luckdraw
if (item.info.type == '未中奖') {
wx.showModal({
title: item.info.title,
content: `好可惜啊,就差一点就中奖了呢!试试换个姿势再试一次呢!`,
showCancel: false
})
return
}
wx.showModal({
title: '恭喜中奖',
content: `恭喜抽中【${item.info.title}】-${item.info.subTitle},请等待奖品发放!`,
showCancel: false
})
}
})
效果
更多推荐
所有评论(0)