vue3.0+TypeScript实现卡片九宫格选中后卡片翻转特效
API:
| 参数 | 说明 | 类型 | 默认值 |
|---|
| intervalTime | 卡片抽奖间隔时间 | number | |
| delayTime | 中奖延迟显示时间 | number | |
| priceWidth | 抽奖卡片的宽度 | number | |
| priceHeight | 抽奖卡片的高度度 | number | |
| circleTime | 抽奖几次之后中奖 | number | |
| circleNum | 抽奖转动的次数 | number | |
| priceId | 中奖ID(需要后台返回) | number | |
抽奖数据API:
| 参数 | 说明 | 类型 | 默认值 |
|---|
| id | 抽奖ID | number | 无 |
| info | 中奖信息 | string | 无 |
| front | 中奖面图片地址 | string | 无 |
| back | 抽奖面图片地址 | string | 无 |
代码示例(父组件):
父组件
<template>
<Lottery :priceList="priceList"></Lottery>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import Lottery from "./../compoments/lottery.vue";
onMounted(() => {
});
const bargainUserVosList = ref([
"1恭喜书友123***5464获得《生命的真相》实体书5折券一张",
"2恭喜书友123***5464获得《生命的真相》实体书5折券一张",
"3恭喜书友123***5464获得《生命的真相》实体书5折券一张",
"4恭喜书友123***5464获得《生命的真相》实体书5折券一张",
"5恭喜书友123***5464获得《生命的真相》实体书5折券一张",
"6恭喜书友123***5464获得《生命的真相》实体书5折券一张",
"7恭喜书友123***5464获得《生命的真相》实体书5折券一张",
]);
interface priceInfo {
intervalTime: number;
delayTime: number;
priceWidth: number;
priceHeight: number;
circleTime: number;
circleNum: number;
priceId: number;
}
interface listInfo {
id?: number;
front?: string;
back?: string;
info?: string;
}
const priceList: listInfo[] = [
{
id: 1,
info: "1元优惠券",
front: "https://XXX.com/activity/smile/is_all.png",
back: "https://XXX.com/activity/smile/all.png",
},
{
id: 2,
info: "10元优惠券",
front: "https://XXX.com/activity/smile/is_person.png",
back: "https://XXX.com/activity/smile/person.png",
},
{
id: 3,
info: "谢谢惠顾",
front: "https://XXX.com/activity/smile/is_good.png",
back: "https://XXX.com/activity/smile/good.png",
},
{
id: 4,
info: "豪华电动车",
front: "https://XXX.com/activity/smile/is_bless.png",
back: "https://XXX.com/activity/smile/bless.png",
},
{
id: 5,
info: "1w购物券",
front: "https://XXX.com/activity/smile/is_agency.png",
back: "https://XXX.com/activity/smile/agency.png",
},
];
const priceOptions = ref<priceInfo>({
intervalTime: 200,
delayTime: 500,
priceWidth: 100,
priceHeight: 140,
circleTime: 3,
circleNum: 20,
priceId: 1,
});
</script>
代码示例(子组件):
<template>
<div class="lottery-container" id="lottery-container"></div>
</template>
<script setup lang="ts">
import { ref, onMounted, defineProps } from "vue"
const drawOrder: any = ref([])
const currentIndex = ref<number | null>(null)
const count = ref(0)
const isDrawing = ref(false)
const circle = ref(20)
const lotteryId = ref(1)
const priceObj = ref<priceInfo>({
intervalTime: 500,
delayTime: 200,
priceWidth: 100,
priceHeight: 140,
circleTime: 3,
circleNum: 20,
priceId: 1,
})
interface listInfo {
id?: number
front?: string
back?: string
info?: string
}
interface priceInfo {
// 抽检间隔时间
intervalTime: number
// 中奖延迟显示时间
delayTime: number
// 中间显示奖品宽度
priceWidth: number
// 中间显示奖品高度
priceHeight: number
// 抽奖次数
circleTime: number
// 抽奖循环次数
circleNum: number
// 中奖Id
priceId: number
}
const props = defineProps({
priceParameter: {
type: Object as () => priceInfo,
default: () => ({
intervalTime: 50,
delayTime: 200,
priceWidth: 100,
priceHeight: 140,
circleTime: 3,
circleNum: 20,
priceId: 1,
}),
},
priceList: {
type: Array<listInfo>,
default: () => [],
},
})
onMounted(() => {
customOrder()
createDiv()
conductLottery()
})
// 创建所需要的抽奖的卡片个数
function createDiv() {
let parentElement = document.getElementById("lottery-container") as any
parentElement.innerHTML = props.priceList
.map((v, index) => {
return `<div class = "lottery-con-item">
<div class = "lottery-item-box front"></div>
<div class = "lottery-item-box back"></div>
</div>`
})
.join("")
let childElement = document.getElementsByClassName("lottery-con-item") as any
let allElement = document.getElementById("lottery-container")?.children as any
for (let i = 0
allElement[i].style.width = Number(props.priceParameter.priceWidth) / 37.5 + "rem"
allElement[i].style.height = Number(props.priceParameter.priceHeight) / 37.5 + "rem"
}
for (let i = 0
childElement[drawOrder.value[i]].children[0].style.backgroundImage = `url(${props.priceList[i].front})`
childElement[drawOrder.value[i]].children[1].style.backgroundImage = `url(${props.priceList[i].back})`
}
let childHeight = childElement[0].offsetHeight + 15
parentElement.style.height = `${(2 * childHeight) / 37.5}rem`
}
// 自定义排序
function customOrder() {
let listArr: any = []
props.priceList.forEach((val, index) => {
listArr.push(index)
})
// 自定义排序函数
listArr.sort((a: number, b: number) => {
// 定义目标顺序数组
const order = [9, 10, 11, 6, 7, 8, 3, 4, 5, 0, 1, 2]
// 获取元素在目标顺序数组中的索引
const indexA = order.indexOf(a)
const indexB = order.indexOf(b)
// 如果元素不在目标顺序数组中,放在后面
if (indexA === -1) return 1
if (indexB === -1) return -1
// 根据目标顺序数组的索引进行排序
return indexA - indexB
})
drawOrder.value = listArr
}
// 进行抽奖
const conductLottery = () => {
var allChild = document.getElementsByClassName("lottery-con-item")
const timer = setInterval(() => {
currentIndex.value = drawOrder.value[count.value % drawOrder.value.length]
count.value++
for (let i = 0
if (i == currentIndex.value) {
allChild[currentIndex.value].classList.add("lottery-con-item-acitive")
} else {
allChild[i].classList.remove("lottery-con-item-acitive")
}
}
if (count.value > circle.value && currentIndex.value === drawOrder.value[lotteryId.value - 1]) {
// 抽奖结束
clearInterval(timer)
// 停顿一会显示中奖
setTimeout(() => {
count.value = 0
currentIndex.value = null
let turnBoxChildren = document.getElementsByClassName(`lottery-con-item-acitive`)
turnBoxChildren[0].children[0].classList.add("lottery-animation1")
turnBoxChildren[0].children[1].classList.add("lottery-animation2")
}, props.priceParameter.intervalTime)
}
}, props.priceParameter.delayTime)
}
</script>
<style>
.lottery-container {
display: flex
justify-content: space-evenly
flex-wrap: wrap-reverse
width: 100%
min-height: 400px
box-sizing: border-box
/* background-color: red
}
.lottery-con-item {
position: relative
transform-style: preserve-3d
}
.lottery-con-item-acitive {
transform: scale(1.1)
}
.lottery-item-box {
position: absolute
top: 0
left: 0
width: 100%
height: 100%
background-size: 100% 100%
backface-visibility: hidden
}
.lottery-item-box.fornt {
width: 100%
height: 100%
animation: backface 1s ease-in-out 0.5s normal forwards
}
.lottery-item-box.back {
width: 100%
height: 100%
backface-visibility: hidden
}
.lottery-animation1 {
transform: rotateY(180deg)
animation: lottery-backface 1s ease-in-out normal forwards
}
.lottery-animation2 {
animation: lottery-backface1 1s ease-in-out normal forwards
}
@keyframes lottery-backface {
100% {
transform: rotateY(0)
}
}
@keyframes lottery-backface1 {
100% {
transform: rotateY(180deg)
}
}
</style>