先给大家看一下样式。
无数次在面对需求手足无措的时候站在了巨人的肩上看到了更大的世界,所以这次也把自通过修改现成的组件而收获的内容分享给大家。
源组件参考自大转盘抽奖 | 基于 Js / TS / Vue / React / 微信小程序 / uni-app / Taro 的【大转盘 & 九宫格 & 老虎机】抽奖插件 如果大家有不同形式的抽奖需求可以在这里找找看
下面开始分享代码内容,首先,在uniapp插件市场中找到这个插件,然后用自己习惯的方式进行安装。lucky-canvas【大转盘|九宫格|老虎机】抽奖插件 - DCloud 插件市场
需求背景:
小弟的需求背景是为小程序应用的用户做活动拉新,用户登陆进来,授权手机号即可获得一次抽奖机会;用户完善个人信息后又可获得一次抽奖机会;最后用户首次购买商品后可再获得一次抽奖机会。
用户进入页面中先输入手机号,即可查看到自己当前有几次抽奖机会,点击抽奖按钮即可开始抽奖,抽奖结果会以弹窗的方式展示,在“我的奖品”中可以查看到用户的获奖情况,点击切换账号。
前端页面(样式也会放下下面):
<template>
<view class="content">
<!-- 为了加背景 -->
<uni-popup class="popwin" ref="popup" type="center" borderRadius="10px" backgroundColor="#fff" maskClick="true">
<view class="mention">输入手机号即可参与抽奖</view>
<input class="popinput" placeholder="请输入手机号" v-model="phoneNum">
<button class="btn" @click="checkNum">确定</button>
</uni-popup>
<view class="fordecr">
<view class="mynum" @click="myAccount">
<view class="prizetext">切换账号</view>
</view>
<view class="myprize" @click="myPrize">
<image src="../../static/img/prizeicon.webp"></image>
<view class="prizetext">我的奖品</view>
</view>
<!-- 幸运转盘 -->
<LuckyWheel class="luckywheel" ref="myLucky" width="700rpx" height="700rpx" :blocks="blocks"
:prizes="prizes" :buttons="buttons" :defaultStyle="defaultStyle" @start="startCallBack"
@end="endCallBack"/>
<!-- 剩余抽奖次数 -->
<view class="remain">剩余抽奖次数:{{remainChance}}</view>
<!-- 活动须知 -->
<view class="toknow">
<image class="announceicon" src="../../static/img/announced.png"></image>
<view class="readtitle">活动须知</view>
<view class="readcontent">
<view class="minitit">抽奖规则:</view>
1、新用户首次注册后即可获得一次抽奖机会
<view class="status" v-if="this.register == 0">(未完成)</view>
<view class="status" v-if="this.register == 1">(待抽奖)</view>
<view class="status" v-if="this.register == 2">(已抽奖)</view>
;<br>
2、用户完善基础信息后可获得一次抽奖机会
<view class="status" v-if="this.register == 0">(未完成)</view>
<view class="status" v-if="this.register == 1">(待抽奖)</view>
<view class="status" v-if="this.register == 2">(已抽奖)</view>
;<br>
3、首次购买商品可获得一次抽奖机会(仅限首次购买)
<view class="status" v-if="this.register == 0">(未完成)</view>
<view class="status" v-if="this.register == 1">(待抽奖)</view>
<view class="status" v-if="this.register == 2">(已抽奖)</view>
。<br>
<view class="minitit" style="margin-top:10px">兑奖须知:</view>
每人仅限当天凭本人获奖页面现场领取奖品。
</view>
</view>
</view>
</view>
</template>
js代码部分:
<script>
import LuckyWheel from '@/components/@lucky-canvas/uni/lucky-wheel' // 大转盘
export default {
components: {
LuckyWheel
},
data() {
return {
blocks: [{
padding: '10px',
background: '#f7cf7f'
},
{
padding: '10px',
background: '#ec9447'
},
],
prizename: [],
prizes: [],
buttons: [{
radius: '45px',
background: '#f19b38'
},
{
radius: '35px',
background: '#fed58e'
},
{
radius: '30px',
background: '#ee6642',
pointer: true,
fonts: [{
text: '开始\n抽奖',
top: '-20px',
fontColor: '#fff'
}],
},
],
defaultStyle: [{
background: '#fef4e0'
}],
remainChance: 0, //当前用户的剩余次数
phoneNum: '', //电话号码
register:0, //注册标记
inform:0, //个人信息完善标记
shopping:0, //是否购物标记
prizeIndex:0, //中奖序号
isAllowed:true //是否允许抽奖
}
},
onLoad(param) {
// 从我的奖品页面跳转过来的话避免直接刷新把用户的phoneNum给清掉,两个页面之间相互传递
console.log('这是onload的param',param)
if (param.phone){
this.phoneNum = param.phone
}
},
onReady() {
// 如果当前手机号码不为空,那么在调用查询剩余抽奖次数接口
if (this.phoneNum !== ""){
this.checkNum()
}
// 否则弹出输入手机号的弹框让用户输入
else{
this.open()
}
// 获取奖池奖品名称的接口
this.getPrizePool()
},
methods: {
open() {
this.$refs.popup.open()
},
close() {
this.$refs.popup.close()
},
myAccount(){
this.phoneNum = ""
this.open()
},
// 调用查询有多少次抽奖机会的接口
async checkNum() {
const res = await this.$myRequest({
url:'查询有多少次抽奖机会的api地址'
})
console.log('这是checkNum',res)
if (res.data.success == true){
this.remainChance = res.data.data.chanceCount
this.register = res.data.data.register
this.inform = res.data.data.inform
this.shopping = res.data.data.shopping
}
this.close()
},
// 查询奖池
async getPrizePool(){
const res = await this.$myRequest({
url:'查询共有多少种奖品的url'
})
if (res.data.success == true){
res.data.data.map(item=>{
this.prizename.push(item.award)
})
this.initPrize()
}
else{
uni.showToast({
title:res.data.desc
})
}
// console.log('这是获取奖池',res,this.prizename)
},
// 初始化所有奖项数组
initPrize() {
// 获取所有奖项的名字数组的长度
const arrayLength = this.prizename.length
// 构造数组基本解构,然后往里填充
this.prizes = new Array(arrayLength).fill().map(() => ({
fonts: [{
text: '',
top: '10%'
}],
background: ''
}));
// 循环8次
for (var i = 0; i < arrayLength; i++) {
// 将奖项名称赋到prizes数组中
this.prizes[i].fonts[0].text = this.prizename[i]
// console.log('this is prizes[' + i + ']的text:', this.prizes[i].fonts[0].text)
// 奇数个背景颜色和偶数个的区分开
if (i % 2 == 0) {
this.prizes[i].background = "#f8dca8"
} else {
this.prizes[i].background = "#fef4e0"
}
console.log('这是prizes[]', this.prizes)
}
},
// 点击抽奖按钮触发回调
startCallBack() {
// 如果当前抽奖机会>剩余
if (this.remainChance > 0 ) {
if (this.isAllowed == false){
uni.showToast({
title:'请稍后再试!'
})
return;
}
// 先开始旋转
this.$refs.myLucky.play()
this.isAllowed = false
// 使用定时器来模拟请求接口
setTimeout(() => {
// 注意一定要在setTimeout里面给isAllowed赋值可以做到一定程度的防抖
this.isAllowed = true
this.submitRes()
console.log('this.prizeIndex',this.prizeIndex)
// 调用stop停止旋转并传递中奖索引
}, 2500)
} else {
uni.showToast({
title: '您当前暂无抽奖机会!'
})
}
},
// 提交抽奖的动作,并获取抽奖结果
async submitRes(){
const res = await this.$myRequest({
url:'抽奖行为的api地址',
method:'POST',
data:{
code:'20241016',
phone:this.phoneNum
}
})
console.log('这是获取抽奖结果',res)
if (res.data.success == true){
console.log('这是res.data.data.index',res.data.data.index)
this.prizeIndex = res.data.data.index
this.$refs.myLucky.stop(this.prizeIndex)
// 抽奖后次数一定要记得--
this.remainChance--
}else{
uni.showToast({
title:res.data.desc
})
return
}
},
// 抽奖结束触发回调
endCallBack() {
// 奖品详情
var prize = this.prizes[this.prizeIndex]
console.log('这是获奖情况', prize.fonts[0].text)
console.log('这是回调函数的prize',prize)
// 弹出获奖结果提示
uni.showModal({
title: '恭喜您获得' + prize.fonts[0].text
})
},
// 跳转到我的奖品页面
myPrize() {
uni.navigateTo({
url: '/pages/myprize/myprize?phone='+this.phoneNum
})
}
}
}
</script>
下面是css样式:
<style lang="scss" scoped>
.content {
border: 1px solid transparent;
background: url(../../static/img/bg.png) no-repeat;
background-size:100vw 100vh;
.popinput {
margin: 10px 20px;
border: 1px solid #dedede;
border-radius: 5px;
height: 40px;
width: 200px;
padding-left: 5px;
}
.btn {
width: 100px;
height: 40px;
background-color: #ee6642;
color: #fff;
margin-bottom: 20px;
margin-top: 20px;
line-height: 40px;
}
.mention {
margin-top: 20px;
margin-left: 20px;
margin-right: 20px;
}
.fordecr {
background: url(../../static/img/caidai.png);
background-size: 100vw;
width: 100vw;
height: 100vh;
.mynum{
line-height: 40px;
left: 10px;
top:10px;
position:absolute;
text-decoration: underline;
color: #B04343;
}
.myprize {
position: absolute;
right: 10px;
text-decoration: underline;
top: 10px;
color: #B04343;
line-height: 50px;
display: flex;
image {
width: 40px;
height: 40px;
}
.prizetext{
line-height: 40px;
}
}
.luckywheel {
margin-top: 30px;
}
.remain {
text-align: center;
line-height: 60px;
}
.toknow {
width: 600rpx;
margin-left: auto;
margin-right: auto;
margin-top: 10px;
border-radius: 20px;
background: linear-gradient(90deg, #FAE5CF, #FFFEF0 50%, #FAE5CF);
box-shadow: -1px 1px 4px #9a9a9a;
line-height: 30px;
position: relative;
.announceicon {
position: absolute;
left: 8px;
top: 7px;
width: 40px;
height: 35px;
}
.readtitle {
border-top-left-radius: 20px;
border-top-right-radius: 20px;
text-align: center;
font-size: 20px;
line-height: 50px;
font-weight: 600;
background-color: #B04343;
color: #fff;
letter-spacing: 3px;
}
.minitit {
font-weight: 600;
}
.status{
display:inline-block !important;
color:#8a8a8a;
}
.readcontent {
padding: 10px;
}
}
}
}
</style>
下面一个页面就是我的奖品页面,简单给大家看一下全部代码就不细说了:
<template>
<view class="content">
<view class="title">我的奖品</view>
<view class="playwheel" @click="playWheel">返回抽奖</view>
<view class="nodata" v-if="noaward">
<image src="../../static/img/noaward.png"></image>
<view class="mention">当前暂无奖品,祝您好运!</view>
</view>
<view class="prizelist" v-if="!noaward">
<view class="prizeitem" v-for="(item,index) in prizeList" :key="index">
<view class="left">
<image src="../../static/img/prize.png"></image>
</view>
<view class="right">
<view class="name">奖品:{{item.award}}</view>
<view class="time">时间:{{item.time}}</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
prizeList: [],
phoneNum:'',
noaward:true
}
},
onLoad(param){
this.phoneNum = param.phone
console.log('这是phoneNum',param)
this.getRecord(this.phoneNum)
},
methods: {
playWheel() {
uni.navigateTo({
url:'/pages/index/index?phone='+this.phoneNum,
})
},
async getRecord(a){
const res = await this.$myRequest({
url:'查询我的奖品api的地址',
data:{
code:20241016,
phone:a
}
})
console.log('这是获奖记录',res)
if (res.data.success == true){
this.prizeList = res.data.data
if(res.data.data.length == 0){
this.noaward = true
}
else{
this.noaward = false
}
}
else{
uni.showToast({
title:res.data.desc
})
}
}
}
}
</script>
<style lang="scss" scoped>
.content {
width: 100vw;
height: 100vh;
background: url(../../static/img/bg.png) no-repeat;
background-size:100vw 100vh;
.playwheel {
position: absolute;
right: 10px;
top: 20px;
text-decoration: underline;
color: #B04343;
}
.nodata{
display: block;
text-align: center;
margin-left:auto;
margin-right:auto;
image{
width:600rpx;
height:600rpx;
}
.mention{
font-size:20px;
}
}
// text-align: center;
.title {
text-align: center;
line-height: 60px;
font-size: 20px;
}
.prizelist {
width: 600rpx;
margin-left: auto;
margin-right: auto;
background: rgba(255, 255, 255, 0.6);
border-radius: 20px;
box-shadow: 0 2px 4px #dedede;
.prizeitem {
border-bottom: 1px solid #dedede;
display: flex;
height: 80px;
.left {
image {
width: 80px;
height: 70px;
margin-top: 10px;
}
}
.right {
margin-top: 10px;
.name {
line-height: 30px;
}
.time {
line-height: 30px;
}
}
}
.prizeitem:last-child {
border: none;
}
}
}
</style>