转载
转盘抽奖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
[v-cloak] {
display: none;
}
.container {
width: 540px;
height: 540px;
margin: 100px auto;
position: relative;
}
.prize-list {
width: 100%;
height: 100%;
border-radius: 50%;
border: 10px solid #98d3fc;
overflow: hidden;
}
.prize-item {
position: absolute;
left: 0;
right: 0;
top: -10px;
margin: auto;
}
.prize-item img {
width: 30%;
height: 20%;
margin: 40px auto 10px;
display: block;
}
.prize-item p {
color: #fff;
font-size: 12px;
text-align: center;
line-height: 20px;
}
.btn {
width: 160px;
height: 160px;
background: url('https://www.jq22.com/demo/jquerylocal201912122316/img/btn_lottery.png') no-repeat center / 100% 100%;
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
cursor: pointer;
}
.btn::before {
content: "";
width: 41px;
height: 39px;
background: url('https://www.jq22.com/demo/jquerylocal201912122316/img/icon_point.png') no-repeat center / 100% 100%;
position: absolute;
left: 0;
right: 0;
top: -33px;
margin: auto;
}
</style>
</head>
<body>
<div id="app" v-cloak>
<div class="container">
<div class="prize-list" ref="prizeWrap" :style="bgColor">
<div class="prize-item" v-for="(item, index) in prizeList" :style="prizeStyle(index)">
<img :src="item.pic" alt="">
<p>{{ item.name }}</p>
</div>
</div>
<div class="btn" @click="start"></div>
</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const { createApp, onMounted, onUnmounted, ref, reactive, toRefs, computed, nextTick } = Vue
createApp({
setup () {
const state = reactive({
prizeList: [
{ name: '手机', pic: 'https://bkimg.cdn.bcebos.com/pic/3801213fb80e7bec54e7d237ad7eae389b504ec23d9e' },
{ name: '手表', pic: 'https://img1.baidu.com/it/u=2631716577,1296460670&fm=253&fmt=auto&app=120&f=JPEG' },
{ name: '苹果', pic: 'https://img2.baidu.com/it/u=2611478896,137965957&fm=253&fmt=auto&app=138&f=JPEG' },
{ name: '棒棒糖', pic: 'https://img2.baidu.com/it/u=576980037,1655121105&fm=253&fmt=auto&app=138&f=PNG' },
{ name: '娃娃', pic: 'https://img2.baidu.com/it/u=4075390137,3967712457&fm=253&fmt=auto&app=138&f=PNG' },
{ name: '木马', pic: 'https://img1.baidu.com/it/u=2434318933,2727681086&fm=253&fmt=auto&app=120&f=JPEG' },
{ name: '德芙', pic: 'https://img0.baidu.com/it/u=1378564582,2397555841&fm=253&fmt=auto&app=120&f=JPEG' },
{ name: '玫瑰', pic: 'https://img1.baidu.com/it/u=1125656938,422247900&fm=253&fmt=auto&app=120&f=JPEG' }
],
isRunning: false,
baseRunAngle: 360 * 5,
prizeId: 0,
})
const prizeWrap = ref(null)
const rotateAngle = computed(() => {
const _degree = 360 / state.prizeList.length
return _degree
})
const totalRunAngle = computed(() => {
return state.baseRunAngle + 360 - state.prizeId * rotateAngle.value - rotateAngle.value / 2
})
const bgColor = computed(() => {
const _len = state.prizeList.length
const colorList = ['#5352b3', '#363589']
let colorVal = ''
for (let i = 0; i < _len; i++) {
colorVal += `${colorList[i % 2]} ${rotateAngle.value * i}deg ${rotateAngle.value * (i + 1)}deg,`
}
return `
background: conic-gradient(${colorVal.slice(0, -1)});
`
})
const prizeStyle = computed(() => {
const _degree = rotateAngle.value
return (i) => {
return `
width: ${2 * 270 * Math.sin(_degree / 2 * Math.PI / 180)}px;
height: 270px;
transform: rotate(${_degree * i + _degree / 2}deg);
transform-origin: 50% 100%;
`
}
})
onMounted(() => {
prizeWrap.value.style = `${bgColor.value} transform: rotate(-${rotateAngle.value / 2}deg)`
})
onUnmounted(() => {
prizeWrap.value.removeEventListener('transitionend', stopRun)
})
const getRandomNum = () => {
const num = Math.floor(Math.random() * state.prizeList.length)
return num
}
const start = () => {
if (!state.isRunning) {
state.isRunning = true
console.log('开始抽奖,后台请求中奖奖品')
const prizeId = getRandomNum()
console.log('中奖ID>>>', prizeId, state.prizeList[prizeId])
state.prizeId = prizeId
startRun()
}
}
const startRun = () => {
console.log(state.isRunning, totalRunAngle.value)
prizeWrap.value.style = `
${bgColor.value}
transform: rotate(${totalRunAngle.value}deg);
transition: all 4s ease;
`
prizeWrap.value.addEventListener('transitionend', stopRun)
}
const stopRun = (e) => {
console.log(e)
state.isRunning = false
prizeWrap.value.style = `
${bgColor.value}
transform: rotate(${totalRunAngle.value - state.baseRunAngle}deg);
`
}
return {
...toRefs(state),
bgColor,
prizeStyle,
prizeWrap,
start
}
}
}).mount('#app')
</script>
</body>
</html>
九宫格抽奖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
[v-cloak] {
display: none;
}
.container {
width: 450px;
height: 450px;
background: #98d3fc;
border: 1px solid #98d3fc;
margin: 100px auto;
display: flex;
flex-wrap: wrap;
justify-content: space-around;
align-items: center;
}
.item {
width: 140px;
height: 140px;
border: 2px solid #fff;
position: relative;
}
.item:nth-of-type(5) {
cursor: pointer;
}
.item img {
width: 100%;
height: 100%;
}
.item p {
width: 100%;
height: 20px;
background: rgba(0, 0, 0, 0.5);
color: #fff;
font-size: 12px;
text-align: center;
line-height: 20px;
position: absolute;
left: 0;
bottom: 0;
}
.active {
border: 2px solid red;
box-shadow: 2px 2px 30px #fff;
}
</style>
</head>
<body>
<div id="app" v-cloak>
<div class="container">
<div :class="['item', {'active': currentIndex === index}]"
v-for="(item, index) in prizeList"
@click="start(index)">
<img :src="item.pic" alt="">
<p v-if="index !== 4">{{ item.name }}</p>
</div>
</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
const { createApp, onMounted, ref, reactive, toRefs, computed } = Vue
createApp({
setup () {
const state = reactive({
prizeList: [
{ name: '手机', pic: 'https://bkimg.cdn.bcebos.com/pic/3801213fb80e7bec54e7d237ad7eae389b504ec23d9e' },
{ name: '手表', pic: 'https://img1.baidu.com/it/u=2631716577,1296460670&fm=253&fmt=auto&app=120&f=JPEG' },
{ name: '苹果', pic: 'https://img2.baidu.com/it/u=2611478896,137965957&fm=253&fmt=auto&app=138&f=JPEG' },
{ name: '棒棒糖', pic: 'https://img2.baidu.com/it/u=576980037,1655121105&fm=253&fmt=auto&app=138&f=PNG' },
{ name: '娃娃', pic: 'https://img2.baidu.com/it/u=4075390137,3967712457&fm=253&fmt=auto&app=138&f=PNG' },
{ name: '木马', pic: 'https://img1.baidu.com/it/u=2434318933,2727681086&fm=253&fmt=auto&app=120&f=JPEG' },
{ name: '德芙', pic: 'https://img0.baidu.com/it/u=1378564582,2397555841&fm=253&fmt=auto&app=120&f=JPEG' },
{ name: '玫瑰', pic: 'https://img1.baidu.com/it/u=1125656938,422247900&fm=253&fmt=auto&app=120&f=JPEG' }
],
currentIndex: 0,
isRunning: false,
speed: 10,
timerIns: null,
currentRunCount: 0,
totalRunCount: 32,
prizeId: 0,
})
const startBtn = { name: '开始按钮', pic: 'https://img2.baidu.com/it/u=1497996119,382735686&fm=253' }
const prizeSort = [0, 1, 2, 5, 8, 7, 6, 3]
const totalRunStep = computed(() => {
return state.totalRunCount + prizeSort.indexOf(state.prizeId)
})
onMounted(() => {
state.prizeList.splice(4, 0, startBtn)
console.log(state.prizeList)
})
const getRandomNum = () => {
return prizeSort[Math.floor(Math.random() * prizeSort.length)]
}
const start = (i) => {
if (i === 4 && !state.isRunning) {
state.currentRunCount = 0
state.speed = 100
state.isRunning = true
console.log('开始抽奖,后台请求中奖奖品')
setTimeout(() => {
const prizeId = getRandomNum()
console.log('中奖ID>>>', prizeId, state.prizeList[prizeId])
state.prizeId = prizeId
}, 2000)
startRun()
}
}
const startRun = () => {
stopRun()
console.log(state.currentRunCount, totalRunStep.value)
if (state.currentRunCount > totalRunStep.value) {
state.isRunning = false
return
}
state.currentIndex = prizeSort[state.currentRunCount % 8]
if (state.currentRunCount > Math.floor(state.totalRunCount * 2 / 3)) {
state.speed = state.speed + Math.floor(state.currentRunCount / 3)
console.log('速度>>>>', state.speed)
}
state.timerIns = setTimeout(() => {
state.currentRunCount++
startRun()
}, state.speed)
}
const stopRun = () => {
state.timerIns && clearTimeout(state.timerIns)
}
return {
...toRefs(state),
start
}
}
}).mount('#app')
</script>
</body>
</html>