Vue3实现九宫格抽奖(思路+完整代码) |
您所在的位置:网站首页 › 有什么抽奖的方法 › Vue3实现九宫格抽奖(思路+完整代码) |
目录 前言 一、实现思路 1.组件结构 2.数据结构 ①奖品列表 ②抽奖按钮 ③v-for的抽奖列表 3.组件交互 ①抽奖顺序 ②奖品高亮 ③中奖 二、完整代码 前言虽然有一些抽奖插件比如lucky-canvas来帮助我们快速发开抽奖小活动,但一些高定制的项目,只能自己手写抽奖(组件构成复杂,插件的css满足不了),今天记录一个九宫格抽奖demo,走一遍抽奖活动设计思路。 一、实现思路假设要实现如下的效果图:(网上截的图,css意思意思就行,具体项目按照设计稿来) 九宫格抽奖的组件结构很简单。首先肯定要有一个父盒子容器,来存放奖品和抽奖按钮。所以优先使用flex布局。 接着就是各种不同的奖品item,和抽奖按钮安置其中。推荐用v-for循环出来(也可以直接手写出来9个奖品盒子)。具体prize-item的盒子里面有什么,取决于需求。以下是参考图简单实现: {{ item.desc }} 2.数据结构 ①奖品列表项目里,奖项有可能是前端固定,也有可能是后台返回的数据,所以放在一个数组里进行管理。 ②抽奖按钮抽奖按钮有可能是文字、图片。还有可能在抽奖过程中改变,所以用一个对象管理。 ③v-for的抽奖列表奖品列表和抽奖按钮加起来,就是完整的渲染列表,由于跟随前两者变化,推荐使用计算属性。 import none from '../assets/none.png' import topPrize from '../assets/top-prize.png' import secondPrize from '../assets/second-prize.png' import thirdPrize from '../assets/third-prize.png' import fourthPrize from '../assets/fourth-prize.png' import redEnvelope from '../assets/red-envelope.png' interface Prize { url: string desc: string } const pirzeList: Prize[] = [ { url: redEnvelope, desc: '现金红包' }, { url: topPrize, desc: '一等奖' }, { url: thirdPrize, desc: '三等奖' }, { url: none, desc: '谢谢参与' }, { url: secondPrize, desc: '二等奖' }, { url: redEnvelope, desc: '现金红包' }, { url: none, desc: '谢谢参与' }, { url: fourthPrize, desc: '四等奖' } ] const btnStart = { url: '', desc: '开始抽奖' } const DrawList = computed(() => { return [...pirzeList.slice(0, 4), btnStart, ...pirzeList.slice(4)] })至此,ui就呈现出来了。 九宫格抽奖一般是顺时针旋转,所以需要一个抽奖顺序,让它按照顺时针进行。(也有随机位置的,那更简单,一个Math.random控制index就可以了。) 而不是按照抽奖列表数组的index进行,那会变成这样: 于是这里专门根据顺时针对应的drawList的index来组成了一个数组drawOrder: const drawOrder = [0, 1, 2, 5, 8, 7, 6, 3] // 抽奖顺序 const currentIndex = ref(null) // 当前选中的奖品 ②奖品高亮专门用一个active类来表示选中高亮,只要抽奖的当前的位置等于列表里面的奖品位置,该项高亮。 首先需要判断只有抽奖列表里面的抽奖按钮才能触发click事件。也就是index===4。 其次开始抽奖后不能再抽奖了,所以需要一个变量表示是否在抽奖。(防抖效果) 最后抽奖次数倒数为0的时候停下中奖。所以需要定义总抽奖次数(多久后停下来) let count = 0 // 抽奖次数 let isDrawing = false // 是否正在抽奖 const circle = 32 // 一圈8个奖品,至少转4圈这里具体是哪个奖品中奖是从后台获取。为了方便,以下代码直接写成第五个。 const draw = (index: number) => { if (index === 4) { // 开始抽奖 if (isDrawing) { return } isDrawing = true const position = 5 // 假设后台返回的中奖位置是5 const timer = setInterval(() => { currentIndex.value = drawOrder[count % drawOrder.length] count++ if (count > circle && currentIndex.value === drawOrder[position - 1]) { // 抽奖结束 clearInterval(timer) // 停顿一会显示中奖 setTimeout(() => { alert('恭喜你中奖了') isDrawing = false count = 0 currentIndex.value = null }, 500) } }, 50) } }中间的逻辑自行替换。需要替换的有: 圈数 --> 时间(可能)position从后台获取 抽奖完成后的其他逻辑 二、完整代码{{ item.desc }} import { ref, computed } from 'vue' import none from '../assets/none.png' import topPrize from '../assets/top-prize.png' import secondPrize from '../assets/second-prize.png' import thirdPrize from '../assets/third-prize.png' import fourthPrize from '../assets/fourth-prize.png' import redEnvelope from '../assets/red-envelope.png' interface Prize { url: string desc: string } const pirzeList: Prize[] = [ { url: redEnvelope, desc: '现金红包' }, { url: topPrize, desc: '一等奖' }, { url: thirdPrize, desc: '三等奖' }, { url: none, desc: '谢谢参与' }, { url: secondPrize, desc: '二等奖' }, { url: redEnvelope, desc: '现金红包' }, { url: none, desc: '谢谢参与' }, { url: fourthPrize, desc: '四等奖' } ] const btnStart = { url: '', desc: '开始抽奖' } const DrawList = computed(() => { return [...pirzeList.slice(0, 4), btnStart, ...pirzeList.slice(4)] }) const drawOrder = [0, 1, 2, 5, 8, 7, 6, 3] // 抽奖顺序 let count = 0 // 抽奖次数 let isDrawing = false // 是否正在抽奖 const currentIndex = ref(null) // 当前选中的奖品 const circle = 32 // 一圈8个奖品,至少转4圈 const draw = (index: number) => { if (index === 4) { // 开始抽奖 if (isDrawing) { return } isDrawing = true const position = 5 // 假设后台返回的中奖位置是5 const timer = setInterval(() => { currentIndex.value = drawOrder[count % drawOrder.length] count++ if (count > circle && currentIndex.value === drawOrder[position - 1]) { // 抽奖结束 clearInterval(timer) // 停顿一会显示中奖 setTimeout(() => { alert('恭喜你中奖了') isDrawing = false count = 0 currentIndex.value = null }, 500) } }, 50) } } .container { width: 528px; height: 528px; background: url('../assets/bg.png') no-repeat; padding: 55px 55px; display: flex; flex-wrap: wrap; justify-content: space-between; align-content: space-between; .prize-item { width: 130px; height: 130px; text-align: center; img { margin-top: 10px; } } .active { background-color: rgb(214, 83, 83); } } |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |