vue实现人员滚动抽奖
实现人员滚动抽奖的Vue方案
核心思路
通过Vue的数据绑定和动画特性,结合JavaScript定时器实现随机滚动效果,最终停在获奖人员位置。
基础实现代码
<template>
<div class="lottery-container">
<div class="lottery-wheel" :style="{ transform: `translateY(${currentPosition}px)` }">
<div v-for="(person, index) in personList" :key="index" class="person-item">
{{ person.name }}
</div>
</div>
<button @click="startLottery" :disabled="isRolling">开始抽奖</button>
</div>
</template>
<script>
export default {
data() {
return {
personList: [
{ name: '张三' },
{ name: '李四' },
// 更多人员...
],
currentPosition: 0,
isRolling: false,
rollSpeed: 50,
targetIndex: 0
}
},
methods: {
startLottery() {
if (this.isRolling) return;
this.isRolling = true;
const duration = 3000 + Math.random() * 2000;
const startTime = Date.now();
const roll = () => {
const elapsed = Date.now() - startTime;
const progress = Math.min(elapsed / duration, 1);
// 减速效果
this.rollSpeed = 50 * (1 - progress * 0.9);
this.currentPosition -= this.rollSpeed;
// 循环滚动
if (-this.currentPosition > this.personList.length * 60) {
this.currentPosition = 0;
}
if (progress < 1) {
requestAnimationFrame(roll);
} else {
this.stopRolling();
}
};
roll();
},
stopRolling() {
this.targetIndex = Math.floor(Math.random() * this.personList.length);
const targetPosition = -this.targetIndex * 60;
// 精确对齐目标位置
const align = () => {
const diff = targetPosition - this.currentPosition;
if (Math.abs(diff) < 1) {
this.currentPosition = targetPosition;
this.isRolling = false;
alert(`中奖者: ${this.personList[this.targetIndex].name}`);
} else {
this.currentPosition += diff * 0.2;
requestAnimationFrame(align);
}
};
align();
}
}
}
</script>
<style scoped>
.lottery-container {
height: 300px;
overflow: hidden;
position: relative;
}
.lottery-wheel {
transition: transform 0.1s linear;
}
.person-item {
height: 60px;
display: flex;
align-items: center;
justify-content: center;
border-bottom: 1px solid #eee;
}
</style>
进阶优化方案
添加视觉效果
增加CSS动画使滚动更平滑:
.lottery-wheel {
transition: transform 0.1s cubic-bezier(0.17, 0.67, 0.21, 0.99);
}
音效增强
添加滚动和停止音效:

// 在methods中添加
playSound(type) {
const audio = new Audio(`/sounds/${type}.mp3`);
audio.play();
}
// 在startLottery和stopRolling中调用
this.playSound('rolling');
this.playSound('stop');
服务端数据集成
从API获取人员名单:
async created() {
try {
const response = await axios.get('/api/lottery/persons');
this.personList = response.data;
} catch (error) {
console.error('获取人员列表失败', error);
}
}
移动端适配方案
添加触摸事件支持:

<div
class="lottery-wheel"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd"
>
methods: {
handleTouchStart(e) {
this.touchStartY = e.touches[0].clientY;
},
handleTouchMove(e) {
if (!this.isRolling) {
const deltaY = e.touches[0].clientY - this.touchStartY;
this.currentPosition += deltaY;
this.touchStartY = e.touches[0].clientY;
}
},
handleTouchEnd() {
// 惯性滚动逻辑
}
}
性能优化建议
-
使用
will-change提升动画性能:.lottery-wheel { will-change: transform; } -
虚拟滚动技术处理超长列表:
// 只渲染可视区域内的项目 visibleItems() { const startIdx = Math.floor(-this.currentPosition / 60); return this.personList.slice(startIdx, startIdx + 10); } -
使用Web Worker处理复杂计算避免主线程阻塞






