feat: 添加抽奖
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
<template>
|
||||
<view
|
||||
class="grid-lottery"
|
||||
:style="{
|
||||
height: gridLotteryHeight,
|
||||
}"
|
||||
>
|
||||
<view class="lottery-list">
|
||||
<view
|
||||
v-for="(item, index) in formateList"
|
||||
:key="item.id"
|
||||
class="lottery-item"
|
||||
:style="{
|
||||
width: `${itemWidth}%`,
|
||||
height: `${itemHeight}${itemHeightUnit}`,
|
||||
transform: `translate(${place(index).x}%, ${place(index).y}${itemHeightUnit})`,
|
||||
}"
|
||||
>
|
||||
<view class="relative">
|
||||
<slot name="lottery-item" :data="item" :index="index" :currIndex="currIndex" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
class="start-button"
|
||||
:style="{
|
||||
left: `${itemWidth}%`,
|
||||
right: `${itemWidth}%`,
|
||||
top: `${itemWidth}%`,
|
||||
bottom: `${itemWidth}%`,
|
||||
}"
|
||||
@tap="onStart"
|
||||
>
|
||||
<slot name="start-button"></slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'GridLottery',
|
||||
props: {
|
||||
// 转盘转动间隔
|
||||
interval: {
|
||||
type: Number,
|
||||
default: 50,
|
||||
},
|
||||
// 是否逐渐减速
|
||||
isIntervalIncrease: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 减速开始时间
|
||||
intervalIncreaseStartTime: {
|
||||
type: Number,
|
||||
default: 3000,
|
||||
},
|
||||
// 最小速度
|
||||
maxInterval: {
|
||||
type: Number,
|
||||
default: 500,
|
||||
},
|
||||
// 奖项外框高度
|
||||
itemHeight: {
|
||||
type: Number,
|
||||
default: 100,
|
||||
},
|
||||
// 高度单位
|
||||
itemHeightUnit: {
|
||||
type: String,
|
||||
default: 'rpx',
|
||||
},
|
||||
// 总数必须为>=8 且被4整除
|
||||
list: {
|
||||
type: Array,
|
||||
default() {
|
||||
// return [
|
||||
// {
|
||||
// id: string,
|
||||
// sort: number
|
||||
// }
|
||||
// ];
|
||||
return []
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
transform: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
},
|
||||
currIndex: 0,
|
||||
startFlag: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
gridLotteryHeight({ itemHeight, formateList, colunmCount, itemHeightUnit }) {
|
||||
return `${itemHeight * ((formateList.length - colunmCount * 2) / 2 + 2)}${itemHeightUnit}`
|
||||
},
|
||||
itemWidth() {
|
||||
return 100 / this.colunmCount
|
||||
},
|
||||
colunmCount() {
|
||||
const len = this.list.length
|
||||
if (len > 8) {
|
||||
return 3 + Math.floor((len - 8) / 4)
|
||||
}
|
||||
return 3
|
||||
},
|
||||
|
||||
formateList() {
|
||||
const len = this.list.length
|
||||
if (len > 7 && (len - 8) % 4 !== 0) {
|
||||
console.warn(
|
||||
'请检查数组,总数必须为>=8 且大余8部分部分能被4整除,如长度为8、12、16...的数组',
|
||||
)
|
||||
}
|
||||
const _list = this.list || []
|
||||
const formateList = _list.sort((a, b) => a.sort - b.sort)
|
||||
return formateList
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// 通过索引获取定位
|
||||
place(index) {
|
||||
const len = this.list.length
|
||||
// 序号
|
||||
const indexToOrder = index + 1
|
||||
if (indexToOrder > this.colunmCount) {
|
||||
// 去除上下行,总行数
|
||||
const rowCount = (len - this.colunmCount * 2) / 2
|
||||
// 非处于左侧
|
||||
if (index > this.colunmCount + rowCount) {
|
||||
// 处于右侧
|
||||
if (indexToOrder > this.colunmCount * 2 + rowCount) {
|
||||
return {
|
||||
x: 0,
|
||||
y: this.itemHeight * (rowCount * 2 + this.colunmCount * 2 - index),
|
||||
}
|
||||
}
|
||||
// 处于底部
|
||||
return {
|
||||
x: 100 * (this.colunmCount * 2 + rowCount - indexToOrder),
|
||||
y: this.itemHeight * (rowCount + 1),
|
||||
}
|
||||
}
|
||||
// 处于右侧
|
||||
return {
|
||||
x: 100 * (this.colunmCount - 1),
|
||||
y: this.itemHeight * (indexToOrder - this.colunmCount),
|
||||
}
|
||||
}
|
||||
// 处于顶部
|
||||
return {
|
||||
x: 100 * index,
|
||||
y: 0,
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 开始抽奖
|
||||
* @param {string|number} id 获奖id
|
||||
* @param {number} minTime 转盘最小持续时间
|
||||
*/
|
||||
async start(id, minTime) {
|
||||
if (this.startFlag) return
|
||||
const len = this.formateList.length
|
||||
const activeIndex = this.formateList.findIndex((item) => item.id === id)
|
||||
if (activeIndex === -1) {
|
||||
const errorText = `没有找到该中奖id ${id}`
|
||||
console.error(errorText)
|
||||
return this.$emit('onError', errorText)
|
||||
}
|
||||
let time = minTime
|
||||
// 动画速度
|
||||
let interval = this.interval
|
||||
const startRotate = () => {
|
||||
this.startFlag = true
|
||||
clearTimeout(this.timer)
|
||||
this.timer = setTimeout(() => {
|
||||
// 抽奖结束
|
||||
if (time < 1 && this.currIndex === activeIndex) {
|
||||
this.startFlag = false
|
||||
clearTimeout(this.timer)
|
||||
return this.$emit('onEnd', this.formateList[activeIndex])
|
||||
}
|
||||
time -= interval
|
||||
if (time < 3000 && this.isIntervalIncrease) {
|
||||
// 调整动画速度
|
||||
interval = interval >= this.maxInterval ? this.maxInterval : interval + 20
|
||||
}
|
||||
this.currIndex = this.currIndex >= len - 1 ? 0 : this.currIndex + 1
|
||||
this.transform = this.place(this.currIndex)
|
||||
return startRotate()
|
||||
}, interval)
|
||||
}
|
||||
startRotate()
|
||||
},
|
||||
onStart() {
|
||||
this.$emit('onStart')
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.grid-lottery {
|
||||
position: relative;
|
||||
.start-button {
|
||||
position: absolute;
|
||||
}
|
||||
.lottery-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.lottery-item {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user