怎么写一个大转盘抽奖
方案一依赖于前后端数据的一致性,如果奖品池的商品有变化,需要 UI + 前端 + 后端 整条链路都进行后续修改,强力推荐方案二
方案一:UI给定背景图,和后端约定id
html 部分:转盘背景需要用 rotateStyle
变量的变化来实现转动
<div class="circle-wrap">
<div class="circle" :style="rotateStyle"></div>
<img @click="beginRotate" class="click-btn" src="http://h0.beicdn.com/open202105/2d87ca2b371447ea_250x250.png" />
</div>
computed 部分:利用计算属性,将rotateStyle
变量的变化转换为 this.rotateAngle
的改变,并给出默认配置项
computed: {
rotateStyle() {
return `-webkit-transition: transform ${this.config.duration}ms ${this.config.mode};
transition: transform ${this.config.duration}ms ${this.config.mode};
-webkit-transform: rotate(${this.rotateAngle}deg);
transform: rotate(${this.rotateAngle}deg);
background: url(${this.config.circleImg}) no-repeat;
background-size: 100% 100%;`;
},
},
const config = {
// 总旋转时间
duration: 3000,
// 旋转圈数
circle: 6,
mode: 'ease-in-out',
circleImg: 'http://h0.beicdn.com/open202105/653083f5e0971dc3_750x722.png'
},
const CIRCLE_ANGLE = 360;
其中 this.circleImg
如下图,奖励背景图
js 计算每个商品需要旋转的角度
const list = [1, 6, 7, 4, 5, 3, 9, 11, 2, 10, 8]; // 对应于UI写死的转盘奖品【逆时针】
// 格式化奖品列表,计算每个奖品的位置
formatPrizeList(list) {
// 记录每个奖的位置
const angleList = [];
const len = list.length;
// 计算单个奖项所占的角度
const average = CIRCLE_ANGLE / len;
list.forEach((item, i) => {
// 记录每个奖项的角度范围
angleList[item] = (i * average);
});
this.angleList = angleList;
return list;
},
js 点击抽奖按钮->调用后端接口->获取抽中的商品的 index
->开始旋转
beginRotate() {
// 避免重复调用接口,并且转盘转完才可以调用下一次接口
if (this.isLoading || this.isRotating) {
return;
}
this.isLoading = true;
api.getGameReward({
act_id: this.actId
}).then((res) => {
this.isLoading = false;
if (res.success && res.data && res.data.is_drawed) {
// 刷新抽奖次数
this.timesNum = res.data.chance || 0;
// 接口若不返回指定奖品,则取奖品1
this.index = res.data..index || 1;
if (this.index) {
// 开始旋转
this.rotating();
return;
}
return;
}
note(res.message || '请稍后再试~');
})
.catch((err) => {
note(err.message || '请稍后再试~');
});
},
js 旋转修改rotateAngle
触发computed
方法,修改转盘旋转角度
// 旋转
rotating() {
const {
isRotating, angleList, config, rotateAngle, index,
} = this;
if (isRotating) {
return;
}
this.isRotating = true;
const len = this.prizeList.length;
const average = CIRCLE_ANGLE / len;
// 计算角度
const angle =
// 初始角度
rotateAngle +
// 多旋转的圈数
(config.circle * CIRCLE_ANGLE) +
// 奖项的角度
angleList[index] -
// 减去上一次转动的角度净值
(rotateAngle % CIRCLE_ANGLE);
this.rotateAngle = angle;
// 旋转结束后,允许再次触发
setTimeout(() => {
this.rotateOver();
}, config.duration + 500);
},
js 旋转结束的时候需要展示中奖的弹窗
// 旋转结束
rotateOver() {
this.isRotating = false;
// 展示中奖弹窗
this.showRewardDialog = true;
},
方案二:后端给定奖品列表【推荐】
由后端传回抽奖商品的列表,在模版遍历展示商品及样式,样式如下
html 模版部分,主要是遍历展示奖品
<div class="wheel-main">
<div class="wheel-bg" :style="rotateStyle">
<div class="prize-list">
// 循环遍历展示不同的奖品
<div
class="prize-item"
v-for="(item, index) in prizeList"
:key="index"
:style="item.style"
>
<div class="prize-name"></div>
<img class="prize-img" :src="item.img"/>
</div>
// 循环展示划分各奖品的划分线
<img class="item-line"
v-for="(item, index) in prizeList"
:key="index"
:style="item.lineStyle"
src="config.lineImg">
</div>
</div>
</div>
computed部分,需要计算的仍旧是中奖后的角度;给出划分奖品的分割线链接
computed: {
rotateStyle() {
return `-webkit-transition: transform ${this.config.duration}ms ${this.config.mode};
transition: transform ${this.config.duration}ms ${this.config.mode};
-webkit-transform: rotate(${this.rotateAngle}deg);
transform: rotate(${this.rotateAngle}deg);`;
},
},
const config = {
lineImg: 'http://h0.beicdn.com/open202018/6e9275e324f838e1_19x235.png'
}
js 计算每个商品需要旋转的角度 – 和方案一不同的是:需要多计算每个奖品和分割线的旋转角度
// 格式化奖品列表,计算每个奖品的位置
formatPrizeList(list) {
// 记录每个奖的位置
const angleList = [];
// 计算单个奖项所占的角度
const len = list.length;
const average = CIRCLE_ANGLE / len;
const half = average / 2;
// 循环计算给每个奖项添加style属性
list.forEach((item, i) => {
// 每个奖项旋转的位置为 当前 i * 平均值 + 平均值 / 2
const angle = -((i * average) + half) + half;
// 增加 style - 奖品+分割线
item.style = `-webkit-transform: rotate(${angle}deg);
transform: rotate(${angle}deg);`;
item.lineStyle = `-webkit-transform: rotate(${angle + half}deg);
transform: rotate(${angle + half}deg);`;
// 记录每个奖项的角度范围
angleList.push((i * average) + half);
});
this.angleList = angleList;
return list;
},
js 点击抽奖按钮->调用后端接口->获取抽中的商品的 index->开始旋转 这里的逻辑和上述一致