想要开发一个,可进行配置奖品的大转盘抽奖活动:如下图:
要求: 转盘底图可配置,相对应的奖品也能够配置
开发思路:
- 可以把转盘开发成一个组件,所有参数皆是可配置的,做成组件具有公用型
- 通过 transform的rotate旋转 以及 transition过渡来实现动画
- 确定旋转实现的原理,不想能像表盘那样指针转,应该是指针不动,表盘旋转,用户体验性更好
具体实现步骤:
1.dom加载完成后,在mounted钩子中写一个transition平移动画
//渲染完了
mounted() {
this.oTurntable = document.querySelector('#turnUl');
// 过度中属性用时5s
this.oTurntable.style.webkitTransition = 'transform ' + this.time / 1000 + 's ease';
},
2.先根据奖品列表数量来计算每个奖品对应的角度,指针一般是定位到该中奖奖品的中心位置,这个要考虑到
autoRotate(arr) {
if (arr.length) {
let len = arr.length;
let base = 360 / len;
arr.forEach((item, index) => {
// 指的是某个奖品区域的中间 : base/2
item.angle = 360 - (base / 2 + index * base);
});
}
return arr;
},
3.点击按钮时请求接口,拿到中奖奖品进行旋转到之前计算好的该奖品的角度,可以写在定时器当中,完成后即清除定时器
// 点击开始,请求接口抽奖
startPlay(){
const a = {
prize: "50元和包券",
id: 4
}
this.startBtn(a)
},
// 开始转动,通过奖项级别进行匹配:id
startBtn(val) {
const self = this
self.activeObj.prizeData.forEach((i,d)=>{
if(i.id == val.id){
self.pIndex = d
}
})
// 拿到相应的角度调旋转接口
self.startrotate(self.activeObj.prizeData[self.pIndex].angle, () => {
self.fulfillHandle(self.activeObj.prizeData[self.pIndex].prize);
});
},
//开始旋转 angle角度 complete回调成功函数
startrotate(angle, complete) {
// 相应的角度 + 满圈 只是在原角度多转了几圈 360 * 6
let rotate = 2160 * (this.rotNum + 1) + angle;
this.oTurntable.style.webkitTransform = 'rotate(' + rotate + 'deg)';
clearTimeout(this.timer);
// 设置5秒后停止旋转,处理接口返回的数据
this.timer = setTimeout(() => {
complete();
this.rotNum++;
}, this.time);
},
//得奖后的处理
fulfillHandle(prizeName) {
this.$emit('result',prizeName)
},
startrotate 这个函数中,通过吧结束处理的函数当做参数进行回调
下面是完整代码:
html:
<template>
<div id="turnBox">
<ul id="turnUl" :style="{ backgroundImage : 'url(' + activeObj.turntableBgc + ')'}">
<li
v-for="(item,index) in activeObj.prizeData"
:key="index"
:style="{webkitTransform: 'rotate(' + -item.angle + 'deg)'}"
>
</li>
</ul>
<img :src="activeObj.turntablebtn" alt="" @click="startPlay" class="turnBtn">
</div>
</template>
js:
<script>
export default {
props: {
activeObj: {
type: Object,
default: null
},
},
data(){
return {
pIndex: 0, // 中奖物品的下标
rotNum: 0, // 旋转圈数基数
time: 5000, // 旋转时间
timer: null, // 定时器
oTurntable: '', // 旋转圆盘背景图
type: 0, // 0 图片 1 汉字
}
},
created() {
this.activeObj.prizeData = this.autoRotate(this.activeObj.prizeData)
console.log(this.activeObj.prizeData);
},
//渲染完了
mounted() {
this.oTurntable = document.querySelector('#turnUl');
// 过度中属性用时5s
this.oTurntable.style.webkitTransition = 'transform ' + this.time / 1000 + 's ease';
},
methods:{
//自动生成角度添加到数组上
autoRotate(arr) {
if (arr.length) {
let len = arr.length;
let base = 360 / len;
arr.forEach((item, index) => {
// 指的是某个奖品区域的中间 : base/2
item.angle = 360 - (base / 2 + index * base);
});
}
return arr;
},
// 点击开始,请求接口抽奖
async startPlay(){
const a = {
prize: "50元和包券",
id: 4
}
this.startBtn(a)
},
// 开始转动,通过奖项级别进行匹配:id
async startBtn(val) {
const self = this
self.activeObj.prizeData.forEach((i,d)=>{
if(i.id == val.id){
self.pIndex = d
}
})
// 拿到相应的角度调旋转接口
self.startrotate(self.activeObj.prizeData[self.pIndex].angle, () => {
self.fulfillHandle(self.activeObj.prizeData[self.pIndex].prize);
});
},
//开始旋转 angle角度 complete回调成功函数
startrotate(angle, complete) {
// 相应的角度 + 满圈 只是在原角度多转了几圈 360 * 6
let rotate = 2160 * (this.rotNum + 1) + angle;
this.oTurntable.style.webkitTransform = 'rotate(' + rotate + 'deg)';
clearTimeout(this.timer);
// 设置5秒后停止旋转,处理接口返回的数据
this.timer = setTimeout(() => {
complete();
this.rotNum++;
}, this.time);
},
//得奖后的处理
fulfillHandle(prizeName) {
this.$emit('result',prizeName)
},
//自动换行
autoWrap(str) {
if (str.length > 5 && str.length <= 10) {
str = str.substring(0, 5) + '<br/>' + str.substring(5, str.length);
} else if (str.length > 10) {
str = str.substring(0, 5) + '<br/>' + str.substring(5, 9) + '...';
}
return str;
}
}
}
</script>
css:
<style lang="less" scoped>
#turnBox {
width: 545px;
height: 544px;
position: relative;
overflow: hidden;
margin: 0px auto;
margin-top: 30px;
background-position: center center;
.turnBtn {
position: absolute;
width: 1.3rem;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-59%);
overflow: hidden;
background-repeat: no-repeat;
background-size: 100% auto;
z-index: 3;
}
ul {
position: absolute;
width: 100%;
height: 100%;
z-index: 1;
background-repeat: no-repeat;
background-size: 100% auto;
li {
position: absolute;
box-sizing: border-box;
// padding-top: 0.5rem;
color: #7e250d;
font-size: 0.3rem;
top: 0pc;
left: 0px;
width: 100%;
height: 100%;
line-height: 20px;
transform-origin: 50% 50%;
img {
position: absolute;
top: 0.3rem;
left: 50%;
transform: translateX(-50%);
width: 20%;
}
}
}
}
</style>