Vue3实现九宫格抽奖(思路+完整代码)

您所在的位置:网站首页 有什么抽奖的方法 Vue3实现九宫格抽奖(思路+完整代码)

Vue3实现九宫格抽奖(思路+完整代码)

2024-07-10 04:35| 来源: 网络整理| 查看: 265

目录

前言

一、实现思路

1.组件结构

2.数据结构

①奖品列表

②抽奖按钮

③v-for的抽奖列表

3.组件交互

①抽奖顺序

②奖品高亮

③中奖

二、完整代码

前言

虽然有一些抽奖插件比如lucky-canvas来帮助我们快速发开抽奖小活动,但一些高定制的项目,只能自己手写抽奖(组件构成复杂,插件的css满足不了),今天记录一个九宫格抽奖demo,走一遍抽奖活动设计思路。

一、实现思路

假设要实现如下的效果图:(网上截的图,css意思意思就行,具体项目按照设计稿来)

1.组件结构

九宫格抽奖的组件结构很简单。首先肯定要有一个父盒子容器,来存放奖品和抽奖按钮。所以优先使用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就呈现出来了。

3.组件交互 ①抽奖顺序

九宫格抽奖一般是顺时针旋转,所以需要一个抽奖顺序,让它按照顺时针进行。(也有随机位置的,那更简单,一个Math.random控制index就可以了。)

 而不是按照抽奖列表数组的index进行,那会变成这样:

于是这里专门根据顺时针对应的drawList的index来组成了一个数组drawOrder:

const drawOrder = [0, 1, 2, 5, 8, 7, 6, 3] // 抽奖顺序 const currentIndex = ref(null) // 当前选中的奖品 ②奖品高亮

专门用一个active类来表示选中高亮,只要抽奖的当前的位置等于列表里面的奖品位置,该项高亮。

.active { background-color: rgb(214, 83, 83); } ③中奖

首先需要判断只有抽奖列表里面的抽奖按钮才能触发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