基于vue3的九宫格抽奖组件
于2023-10-08 22:17:56发布
27
案例下载地址: https://download.csdn.net/download/QQ408896436/87190628
Lottery.vue
<template>
<div class="lottery">
<img :src="config.bg" />
<span ref="lightBtnRef" class="lightBtn" v-show="isShowLightBtn">
<img :src="config.lighturl" :width="config.boxw" :height="config.boxh"/>
</span>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue";
const props = defineProps({
config: {
type: Object,
default() {
return {
bg: "", // 抽奖bg
lighturl: "", // 转动的图片url
total: 0, // 总共有多少奖品
boxw: 0, // 转动图片的宽度
boxh: 0, // 转动图片的高度
pos: "", // 坐标
};
},
},
});
const posArr = props.config.pos.split(","); // 转动图片的位置数组
const isShowLightBtn = ref(false); // 是否显示lightBtn
const isLotterIng = ref(false); // 标记是否正在抽奖
const nowIndex = ref(0); // lightBtn当前的位置
const stayIndex = ref(0); // 抽中的奖品下标
const runStep = ref(0); // 需要转多少次才开始体质
const flag = ref(true);
const lightBtnRef = ref("");
const $emit = defineEmits(["end"]);
// 获取lightBtn的位置
const getPos = () => {
nowIndex.value++;
// 转完一圈
if (nowIndex.value >= props.config.total) {
nowIndex.value = 0;
runStep.value++;
}
// 可以开始停止转盘了(不是马上停止)
if (
runStep.value >= (props.config.maxRunStep || 3) &&
nowIndex.value === stayIndex.value
) {
runStep.value = props.config.maxRunStep || 3;
flag.value = false;
}
// 返回坐标
const nowPos = posArr[nowIndex.value];
const x = nowPos.split("_")[0];
const y = nowPos.split("_")[1];
return {
x,
y,
};
};
// 设置lightBtn的坐标
const setPos = () => {
const p = getPos();
lightBtnRef.value.style.left = p.x + "px";
lightBtnRef.value.style.top = p.y + "px";
};
// 抽奖逻辑
const run = () => {
isShowLightBtn.value = true;
let speed = 50;
let id = 0;
let t = 0;
id = window.setInterval(() => {
// 由慢到快
if (flag.value) {
speed -= 0.1;
} else {
speed += 0.1;
}
// 间隔最小为10
if (speed <= 10) {
speed = 10;
}
// 间隔最大为100
if (speed >= 100) {
speed = 100;
// 停止转动
if (nowIndex.value === stayIndex.value) {
clearInterval(id);
$emit("end", nowIndex.value);
// 属性重置
runStep.value = 0;
flag.value = true;
isLotterIng.value = false;
id = 0;
}
}
t++;
// 不让速度过快
if (t >= speed) {
setPos();
t = 0;
}
}, 0);
};
// 开始抽奖
const start = (stopIndex) => {
if (isLotterIng.value) {
return;
}
isLotterIng.value = true;
stayIndex.value = stopIndex;
run();
};
onMounted(() => {
lightBtnRef.value.style.left = posArr[0].split("_")[0] + "px";
lightBtnRef.value.style.top = posArr[0].split("_")[1] + "px";
});
// 暴露start方法
defineExpose({
start,
});
</script>
<style scoped>
.lottery {
position: relative;
}
.lottery .btn {
position: relative;
display: inline-block;
cursor: pointer;
}
.lottery .lightBtn {
position: absolute;
}
</style>
使用案列
<template>
<div class="app">
<Lottery ref="lotteryRef" :config="lyConfig" @end="end" />
<span
:class="[isLotterIng ? 'lotterycontent_disable' : 'lotterycontent_start']"
@click="lottery"
></span>
</div>
</template>
<script setup>
import { reactive, ref } from "vue";
import picBg from "@/assets/img/bg.png";
import picLightUrl from "@/assets/img/light.png";
import Lottery from "@/components/Lottery.vue";
// 配置
const lyConfig = reactive({
bg: picBg,
lighturl: picLightUrl,
total: 12,
boxw: 154,
boxh: 156,
maxRunStep: 4,
pos: "157_0,313_0,469_0,625_0,781_156,781_312,626_467,470_467,314_467,158_467,1_312,1_156",
});
const lotteryRef = ref("");
const isLotterIng = ref(false);
// 调用抽奖方法
const lottery = () => {
isLotterIng.value = true;
lotteryRef.value.start(parseInt(Math.random() * 12)); // 这里输入中间的数组下标,实际情况是用后端返回的数字
};
// 抽奖完毕后的回调函数
const end = (index) => {
isLotterIng.value = false;
alert(`奖品位置在${index}`);
};
</script>
<style scoped>
.app {
position: relative;
}
.app .lotterycontent_start {
position: absolute;
width: 205px;
height: 54px;
left: 179px;
top: 398px;
display: block;
outline: none;
cursor: pointer;
background: url("@/assets/img/blankstartbtn.png") no-repeat 0 0;
backface-visibility: hidden;
animation: 1s ease 0s infinite alternate none running
lotterycontent_borderLight;
}
.app .lotterycontent_disable {
position: absolute;
width: 205px;
height: 54px;
left: 179px;
top: 398px;
display: block;
outline: none;
background: rgba(0, 0, 0, 0.5);
cursor: default;
}
@keyframes lotterycontent_borderLight {
0% {
box-shadow: 0px 0px 10px 10px rgba(255, 255, 255, 0.3) inset;
}
100% {
box-shadow: 0px 0px 20px 20px rgba(255, 255, 255, 0.6) inset;
}
}
</style>
运行效果