如图效果展示:(因最近双十一,公司需求要给新老客服抽奖发福利,临时写的)
核心代码:
async rotating() { var type = 0; // 默认为 0 转盘转动 1 箭头和转盘都转动(暂且遗留) var during_time = 5; // 默认为1s var result_index = this.index-1; // 最终要旋转到哪一块,对应prize_list的下标 var result_angle = [190 ,139 ,88 ,37 ,-14,-65 ,-116] //这里是指定位置 var rand_circle = 6; // 附加多转几圈,2-3 var rotate_angle = 0; this.count++ if (type == 0) { // 转动盘子 var rateround=rand_circle * 360 + result_angle[result_index] //这里是(转盘算法) rateround是转动的距离 this.start_rtating是每次初始化转盘的位置 rotate_angle =this.start_rotating_degree + rateround -this.start_rotating_degree % 360 ; this.start_rotating_degree = rotate_angle; this.rotate_angle = "rotate(" + rotate_angle + "deg)"; this.lottery_ticket--; let that = this setTimeout(function() { that.game_over(); //提示框 },during_time * 1000 + 1500)// 延时,保证转盘转完 } },
做这个的时候,因为不是很理解转盘算法,第一次点击转盘可以转向指定位置,而第二次后都是有点偏移。这里主要靠 %360来取余,不管你指定位置多少,最终都是要 减去初始位 % 360。
详细代码如下:
<template> <!-- 新客户链接 --> <div class="container"> <div class="draw-title"> <div class="draw-name">{{title}}</div> </div> <div class="lucky-wheel"> <div class="wheel-main"> <div class="wheel-pointer-box"> <div class="wheel-pointer" @click="rotate_handle()" :style="{transform:rotate_angle_pointer,transition:rotate_transition_pointer}"></div> </div> <div class="wheel-bg" :style="{transform:rotate_angle,transition:rotate_transition}"> <div class="prize-list"> <div class="prize-item" v-for="(item,index) in prize_list" :key="index"> <div class="prize-pic"> <!-- <img :src="item.prizeImg"> --> </div> <div class="prize-count"> <span v-if="item.gradeNum!=7">{{item.gradeName}}</span> </div> <div class="prize-text"> <span v-if="item.gradeNum!=7">{{item.prizeName}}</span> </div> <div class="prize-type"> <span v-if="item.gradeNum==7">{{item.gradeName}}</span> </div> </div> </div> </div> </div> </div> <div class="main"> <div class="content"> <div class="lottery_ticket"></div> <div class="scroll_bg"> <ul class="scroll_content" :style="{ top }"> <li v-for="(item,index) in WinList" :key="index" > <el-row> <el-col :span="6">{{index+1}}.{{item.phone | iphone}}</el-col> <el-col :span="14">{{item.prizeGrade.prizeName}}</el-col> <el-col :span="4">{{item.timeAgo}}</el-col> </el-row> </li> </ul> </div> </div> <div class="lotter_foot"> <span class="left" @click="getMyPrizeRecord">我的奖品 ></span> <span class="right" @click="todrawRule">活动规则 ></span> </div> </div> <!-- 输入手机号 --> <div class="toast" v-show="toast_phoneNum"> <div class="toast-container"> <!-- <img :src="toast_pictrue" class="toast-picture"> --> <div class="close" @click="close_phoneNum()"></div> <div class="toast-title"> <span style="margin-right:10px;">手机号:</span> <el-input size="small" style="width:60%;height:0.75rem;" v-model="phoneNum"></el-input> </div> <div class="toast-btn"> <div class="toast-cancel" @click="runDraw">确 认</div> </div> </div> </div> <div class="toast-mask" v-show="toast_phoneNum"></div> <!-- 输入手机号 --> <div class="toast" v-show="toast_myphonecontrol"> <div class="toast-container"> <!-- <img :src="toast_pictrue" class="toast-picture"> --> <div class="close" @click="close_phoneNum()"></div> <div class="toast-title"> <span style="margin-right:10px;">手机号:</span> <el-input size="small" style="width:60%;height:0.75rem;" v-model="phoneNum"></el-input> </div> <div class="toast-btn"> <div class="toast-cancel" @click="runphone">确 认</div> </div> </div> </div> <div class="toast-mask" v-show="toast_myphonecontrol"></div> <!-- 中奖提示 --> <div class="toast" v-show="toast_control"> <div class="toast-container"> <!-- <img :src="toast_pictrue" class="toast-picture"> --> <div class="close" @click="close_toast()"></div> <div class="toast-title"> {{toast_title}} </div> <div class="toast-btn"> <div class="toast-cancel" @click="close_toast">确 认</div> </div> </div> </div> <div class="toast-mask" v-show="toast_control"></div> <!-- 我的奖品 --> <div class="toast" v-show="toast_mycontrol"> <div class="toast-container"> <!-- <img :src="toast_pictrue" class="toast-picture"> --> <div class="close" @click="close_mytoast()"></div> <div class="toast-title"> <div>抽中奖品列表</div> <li v-for="(item,index) in mycontList" :key="index"> {{item.entities.gradeName}}——{{item.luckDrawTime | datetime('date')}} </li> </div> <div class="toast-btn"> <div class="toast-cancel" @click="close_mytoast">确 认</div> </div> </div> </div> <div class="toast-mask" v-show="toast_mycontrol"></div> </div> </template> <script> import {getPrizeActivityById,getPrizeList,startRaffle,checkLuckyDraw,getMyPrizeRecord,getPrizeRecordTopTenList } from '../../api/getData'; export default { data(){ return{ index:0, angle:0, toast_title:'', start_rotating_degree: 0, //初始旋转角度 rotate_angle: 0, //将要旋转的角度 start_rotating_degree_pointer: 0, //指针初始旋转角度(360/分页) rotate_angle_pointer: 0, //指针将要旋转的度数 rotate_transition: "transform 6s ease-in-out", //初始化选中的过度属性控制 rotate_transition_pointer: "transform 12s ease-in-out", //初始化指针过度属性控制 lottery_ticket:1,//抽奖次数 prize_list: [], //奖品列表 toast_control:false, toast_mycontrol:false, click_flag:true, //是否可以旋转抽奖 toast_phoneNum:false, toast_myphonecontrol:false, phoneNum:'', WinList:[],//中奖名单 activeIndex: 0, activityId:null, //用户id mycontList:[], title:'' } }, watch:{ $route(){ console.log(this.$route.query.id) console.log(this.$route.meta.title) } }, methods:{ async getPrizeList(){ const result = await getPrizeList({activityId:this.activityId}) if(result.code == 200){ this.prize_list = result.data }else{ this.$toast({message:result.message ,position:'top'}); } }, rotate_handle(){ this.phoneNum = '' if(!this.phoneNum){ this.toast_phoneNum = true } }, async runDraw(){ if(this.phoneNum.length!=0){ var reg=/^1[3456789]\d{9}$/; if(!reg.test(this.phoneNum)) return this.$toast({message:'请输入有效的手机号码' ,position:'top'}); const result = await checkLuckyDraw({phoneNumber:this.phoneNum,activityId:this.activityId}) if(result.code == 200){ //需要判断 const result = await startRaffle({phoneNumber:this.phoneNum,activityId:this.activityId}) if(result.code == 200){ this.index = result.data.gradeNum; this.rotating() }else{ this.$toast({message:result.message ,position:'top'}); } this.toast_phoneNum = false }else{ this.$toast({message:result.data ,position:'top'}); } }else{ this.$toast({message:'手机号不能为空!' ,position:'top'}); } }, async runphone(){ if(this.phoneNum.length!=0){ var reg=/^1[3456789]\d{9}$/; if(!reg.test(this.phoneNum)) return this.$toast({message:'请输入有效的手机号码' ,position:'top'}); const result = await checkLuckyDraw({phoneNumber:this.phoneNum,activityId:this.activityId}) if(result.code == 500){ //需要判断 this.toast_myphonecontrol = false this.toast_mycontrol = true this.getMyPrizeRecord() }else{ this.$toast({message:result.data ,position:'top'}); } }else{ this.$toast({message:'手机号不能为空!' ,position:'top'}); } }, async rotating() { var type = 0; // 默认为 0 转盘转动 1 箭头和转盘都转动(暂且遗留) var during_time = 5; // 默认为1s var result_index = this.index-1; // 最终要旋转到哪一块,对应prize_list的下标 var result_angle = [190 ,139 ,88 ,37 ,-14,-65 ,-116] var rand_circle = 6; // 附加多转几圈,2-3 var rotate_angle = 0; this.count++ if (type == 0) { // 转动盘子 var rateround=rand_circle * 360 + result_angle[result_index] rotate_angle =this.start_rotating_degree + rateround -this.start_rotating_degree % 360 ; this.start_rotating_degree = rotate_angle; this.rotate_angle = "rotate(" + rotate_angle + "deg)"; this.lottery_ticket--; let that = this setTimeout(function() { that.game_over(); //提示框 },during_time * 1000 + 1500)// 延时,保证转盘转完 } }, game_over() { if(this.prize_list[this.index-1].prizeName=='') return this.toast_control = true; if(this.prize_list[this.index-1].gradeNum ==7){ return this.toast_title = "抽中结果为:"+this.prize_list[this.index-1].gradeName }else{ return this.toast_title = "抽中结果为:"+this.prize_list[this.index-1].prizeName+this.prize_list[this.index-1].gradeName } }, async getMyPrizeRecord(){ if(this.phoneNum){ const result = await getMyPrizeRecord({phoneNumber:this.phoneNum,activityId:this.activityId}) if(result.code == 200){ this.toast_mycontrol = true; this.mycontList = result.data }else{ this.$toast({message:result.message ,position:'top'}); } }else{ this.toast_myphonecontrol = true } }, close_mytoast(){ this.toast_mycontrol = false }, //关闭弹窗 close_toast() { this.toast_control = false; this.getPrizeRecordTopTenList() }, //关闭手机号录入 close_phoneNum(){ this.toast_phoneNum = false; this.toast_myphonecontrol= false }, todrawRule(){ this.$router.push('/newdrawRule?id='+this.$utils.getUrlKey('id')) }, async getPrizeRecordTopTenList(){ const result = await getPrizeRecordTopTenList({activityId:this.activityId}) if(result.code == 200){ this.WinList = result.data }else{ this.$toast({message:result.message ,position:'top'}); } }, async getPrizeActivityById(){ const result = await getPrizeActivityById({id:this.$utils.getUrlKey('id')}) if(result.code == 200){ this.activityId = result.data.id this.title = result.data.name document.title = this.title this.getPrizeList() this.getPrizeRecordTopTenList() }else{ this.$toast({message:result.message ,position:'top'}); } } }, mounted(){ let _this = this; let timer = setInterval(function(){ if(_this.WinList.length){ let b = _this.WinList.shift() _this.WinList.push(b) } }, 2000); this.getPrizeActivityById() }, computed:{ top() { return -this.activeIndex * 1.35 + 'rem' } } } </script> <style lang="less"> .container { width: 100%; background: url("../../assets/img/draw/bgdraw.jpg") no-repeat; background-size: 100% ; .draw-title{ position: absolute; top: 1.225rem; left: 50%; transform: translateX(-50%); background-size: 100% ; width: 90%; height: 3.5625rem; .draw-name{ margin: auto; color: rgb(110,20,54); font-weight: 600; background: rgb(255,228,1); border: .2rem solid rgb(254, 118, 0); border-radius: .2rem; padding: 0.4rem ; text-align: center; } } .lucky-wheel{ width: 100%; height: 42.5625rem; padding-top: 23.5625rem; .wheel-main { display: flex; align-items: center; justify-content: center; position: relative; .wheel-pointer-box { position: absolute; top: 50%; left: 49.2%; z-index: 100; transform: translate(-50%, -50%); width: 18.3125rem; height: 18.3125rem; background: url("../../assets/img/draw/drawtab.png") no-repeat center top; background-size: 100%; .wheel-pointer { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 15.3125rem; height: 15.3125rem; background: url("../../assets/img/draw/drawbtn.png") no-repeat; background-size: 100% 100%; transform-origin: center 60%; } } .wheel-bg { width: 18.4375rem; height: 18.4375rem; background: url("../../assets/img/draw/turntable.png") no-repeat center top; background-size: 100%; transform: rotate(12deg); font-weight: 500; display: flex; flex-direction: column; justify-content: center; align-content: center; transition: transform 3s ease; div { text-align: center; } .prize-list{ width: 100%; height: 100%; position: relative; .prize-item { font-size: 0.45rem; position: absolute; top: 10%; left: 39%; width: 3.9rem; height: 14.5rem; padding-top: 0.5rem; margin: auto; z-index: 2; line-height: 0.85rem; .prize-pic img { width: 4.0625rem; height: 2.5rem; margin-top: 1.5625rem; } .prize-count{ font-size: 0.55rem; } .prize-text { font-size: 0.55rem; } .prize-type { font-size: 0.55rem; padding-top: 1rem; } } .prize-item:first-child { transform: rotate(-194deg); } .prize-item:nth-child(2) { transform: rotate(-140deg); } .prize-item:nth-child(3) { transform: rotate(-88deg); } .prize-item:nth-child(4) { transform: rotate(-38deg); } .prize-item:nth-child(5) { transform: rotate(13deg); } .prize-item:nth-child(6) { transform: rotate(63deg); } .prize-item:nth-child(7) { transform: rotate(114deg); } } } } } .main{ position: relative; width: 100%; padding-bottom: 1.6875rem; .content { position: relative; top: 0.175rem; left: 0; background: url("../../assets/img/draw/winner.png") no-repeat center top; background-size: 100%; width: 100%; height: 12.68rem; margin: auto; font-size: 1.125rem; color: #ffeb39; text-align: center; .lottery_ticket{ height: 4rem; } .scroll_bg{ height: 5.5rem; margin-top: 1.43rem; overflow: hidden; position: relative; .scroll_content{ position: relative; transition: top 0.5s; -webkit-transition: top 0.5s; } ul{ margin:0rem 2rem 1rem; font-size: .55rem; line-height: 1.35rem; // height: 30.14rem; // overflow: scroll; } li{ line-height:1.35rem; } } } .lotter_foot{ color: #fff; z-index: 999; width: 90%; margin:1.8rem auto; font-size: 0.75rem; } } .toast { position: fixed; top: 50%; left: 50%; z-index: 20000; transform: translate(-50%, -50%); width: 15.4375rem; background: #fff; border-radius: 0.3125rem; padding: 0.3125rem; background-color: rgb(252, 244, 224); .toast-container { position: relative; width: 100%; height: 100%; border: 1px dotted #fccc6e; .close { position: absolute; top: -0.9375rem; right: -0.9375rem; width: 2rem; height: 2rem; background: url("../../assets/img/draw/close_store.png") no-repeat center top; background-size: 100%; } .toast-title { padding: 2.8125rem 0; font-size: 0.75rem; color: #fc7939; text-align: center; } .toast-btn { display: flex; align-items: center; justify-content: center; margin-bottom: 0.9375rem; div { background-image: -moz-linear-gradient(-18deg,rgb(242, 148, 85) 0%,rgb(252, 124, 88) 51%, rgb(252, 124, 88) 99%); background-image: -ms-linear-gradient(-18deg,rgb(242, 148, 85) 0%,rgb(252, 124, 88) 51%,rgb(252, 124, 88) 99%); background-image: -webkit-linear-gradient(-18deg,rgb(242, 148, 85) 0%,rgb(252, 124, 88) 51%,rgb(252, 124, 88) 99%); box-shadow: 0px 4px 0px 0px rgba(174, 34, 5, 0.7); width: 4.6875rem; height: 1.875rem; border-radius: 1.875rem; text-align: center; line-height: 1.875rem; color: #fff; } } } } .toast-mask { position: fixed; top: 0; left: 0; background: rgba(0, 0, 0, 0.6); z-index: 1000; width: 100%; height: 100%; } .van-toast van-toast--top van-toast--text{ z-index: 9999; } } </style>