Vue3实现九宫格抽奖效果

news2024/11/24 2:54:07

前言

好久没有写文章了,上一次发文还是年终总结,眨眼间又是一年,每每想多总结却是坚持不来,难顶。  这次分享一个九宫格抽奖小游戏,缘起是最近公司内部做积分抽奖需求,抽出其中抽奖动效做一个总结,从零实现一个抽奖功能的过程和注意点。  Demo功能代码是使用vue3实现的,主要用到了组合式API,由于只是一个简单的demo就没有使用脚手架和打包工具。

需求与效果

需求: 1、礼品根据后台配置生成 2、跑马灯转动效果 3、结果后台生成并且每个礼物概率不一样(概率这里不讨论)

注意点: 1、布局如何排列,是按照跑动排列还是从左至右自上而下排列 2、点击按钮如何插入,DOM结构如何生成 3、跑马效果如何实现,速度如何控制 4、接口如何处理,包括接口报错、请求Pending时特效 5、后台返回结果和跑马完选中结果一致等

最终效果图:

注:图片都是百度图片找的

功能实现

第一步:实现布局

思路:  请求到后台配置的礼物列表,一般是配置了8个礼物,包括谢谢参与,第一种是手动布局写9个礼物div标签,这种方式开始按钮可以直接写到布局里面。第二种可以遍历,这里我使用遍历的方式,但是按钮就需要我们插入到礼物列表数组中去。  css代码可以使用flex布局,三行三列刚好,然后添加所需样式。js部分主要是使用splice()方法插入<开始按钮>。

部分代码:

<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>
</body> 
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' }], // 后台配置的奖品数据
})
const startBtn = { name: '开始按钮', pic: 'https://img2.baidu.com/it/u=1497996119,382735686&fm=253' }

onMounted(() => {// state.prizeList.forEach((item, index) => {//item.id = index// })state.prizeList.splice(4, 0, startBtn)console.log(state.prizeList)
}) 
第二步:实现动效

思路  跑马灯效果的实现主要是转圈高亮,这里我们可以想到当前礼物坐标和跑马执行步数除以8的余数一致时就高亮,但是跟礼物列表渲染的顺序又不一样,所以我们可以定义一个跑马执行的礼物坐标顺序数组 prizeSort = [0, 1, 2, 5, 8, 7, 6, 3],这样就是转圈执行啦。  然后动画一步一步的执行的话我们可以使用一个定时器,然后隔一点时间让当前高亮的下标索引currentIndex变化  转动的圈数我们可以自定义几圈,这里我们用总执行步数计算,必须是8的倍数,比如每次要转4圈,那基本的总执行步数就是32步,再根据后台中奖的礼物坐标计算出还要走多少步加上32即跑马执行的总部数  转动速度的话一般是先快后忙,我们利用定时器setTimeout()方法的话第二个参数的等待时间就要越来越长,可以判断如果执行总步数超过一般或三分之二就开始增加定时器等待时间,让下一步执行越来越慢。

第三步:后台抽奖结果

思路:  后台返回抽奖结果的话,这里可能出现上面注意点问题4和5,接口报错和长时间等待,我们处理方式可以为,点击先请求返回结果再开始动效,对于接口报错我们可以直接提示出来,如何长时间等待我们可以增加一个loading提示,这样就基本可以解决这两个问题了。对于后台返回结果和动效执行完结果如何匹配的问题,上面说过,我们有个基本的执行步数,然后根据请求结果的礼物坐标计算出还要走执行多少步,相加结果就可以匹配上。

代码
<!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 <img src="https://unpkg.com/vue@3/dist/vue.global.js"></script><script> const { createApp, onMounted, ref, reactive, toRefs, computed } = VuecreateApp({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, // 总共跑动次数 8的倍数prizeId: 0, // 中奖id})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.forEach((item, index) => {//item.id = index// })state.prizeList.splice(4, 0, startBtn)console.log(state.prizeList)})// 获取随机数const getRandomNum = () => {// const num = Math.floor(Math.random() * 9)// if (num === 4) {//console.log(">>>>>不能为4")//return getRandomNum()// } else {//return num // }// 这里一次必然可以取到 时间为1次return prizeSort[Math.floor(Math.random() * prizeSort.length)]}const start = (i) => {if (i === 4 && !state.isRunning) {// 重置数据state.currentRunCount = 0state.speed = 100state.isRunning = trueconsole.log('开始抽奖,后台请求中奖奖品')// 请求返回的奖品编号 这里使用随机数 但不能为4// const prizeId = getRandomNum()// console.log('中奖ID>>>', prizeId, state.prizeList[prizeId])// state.prizeId = prizeId// 模拟接口延时返回 如果接口突然报错如何处理?直接调用stopRun()方法停止转动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 = falsereturn}state.currentIndex = prizeSort[state.currentRunCount % 8]// 如果当前步数超过了2/3则速度慢下来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" style="margin: auto" />
</body>
</html> 

最后

整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

部分文档展示:



文章篇幅有限,后面的内容就不一一展示了

有需要的小伙伴,可以点下方卡片免费领取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/169778.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

利用steam搬砖信息差项目,投入不到1万,一个月净赚3万+

老实说&#xff1a;我在做之前没有任何经验&#xff0c;但做梦也没想到&#xff0c;刚开始操作收益就远远超出我的预期&#xff01; 这个账号我才运营了一个月左右&#xff0c;就有3万多的销售额。现在我每月的收入都在上万元&#xff0c;而且随着收益越来越多&#xff0c;操作…

亚马逊云科技re:Invent引领云计算未来方向

亚马逊云科技合作伙伴网络大使计划&#xff0c;吸纳拥有多项亚马逊云科技认证和深入亚马逊云科技知识的合作伙伴成员&#xff0c;协助其成为各个领域的技术专家&#xff0c;开发可供公众使用的内容&#xff0c;如技术写作、博客、开源项目&#xff0c;宣传亚马逊云科技及其合作…

JavaWeb基础(四) JSP介绍

JavaWeb基础(四) JSP介绍 1&#xff0c;JSP 概述 JSP&#xff08;全称&#xff1a;Java Server Pages&#xff09;&#xff1a;Java 服务端页面。是一种动态的网页技术&#xff0c;其中既可以定义 HTML、JS、CSS等静态内容&#xff0c;还可以定义 Java代码的动态内容&#xf…

.shp文件的存储结构是怎样的?底层读取shapefile文件

.shp文件的存储结构是怎样的&#xff1f;底层读取shapefile文件基础知识shp的存储结构python 字节流读取Shp文件基础知识 大家都比较熟悉shp文件&#xff0c;它是GIS软件可以读取的矢量文件。但是大家知道它的存储结构吗&#xff1f;这次带着大家聊聊shp文件的存储结构&#x…

Linux diff 命令

Linux diff 命令用于比较文件的差异。diff 以逐行的方式&#xff0c;比较文本文件的异同处。如果指定要比较目录&#xff0c;则 diff 会比较目录中相同文件名的文件&#xff0c;但不会比较其中子目录。语法diff [-abBcdefHilnNpPqrstTuvwy][-<行数>][-C <行数>][-D…

【Java】【系列篇】【Spring源码解析】【三】【体系】【Resource体系】

主要用于加载配置资源等等Resource 前提须知 ClassLoader类的getResource和getResourceAsStream方法是原生JDK中内置的资源加载文件的方式&#xff1b;Spring中资源模型顶级接口不是Resource&#xff0c;而是InputStreamSource接口&#xff1b;Spring为何自己实现一套资源加载…

Nessus 扫描web服务

系列文章 Nessus介绍与安装 Nessus Host Discovery Nessus 高级扫描 Nessus 扫描web服务 1.启动nessus cd nessus sh qd_nessus.sh2.进入nessus网站 https://192.168.3.47:8834/3.点击【New Scan】 4.点击【Web应用程序测试】 5.输入name【web扫描】&#xff0c;描述【web…

Lesson 2. 矩阵运算基础、矩阵求导与最小二乘法

文章目录一、NumPy 矩阵运算基础1. NumPy 中的矩阵表示2. NumPy 中特殊矩阵构造方法3. NumPy 中矩阵基本运算4. NumPy 中矩阵代数运算二、矩阵方程与向量求导方法1. 方程组求解与矩阵方程求解2. 向量求导运算2.1 向量求导基本方法2.2 常见向量求导公式三、最小二乘法的推导过程…

Vue3 函数式组件的开发方式

声明式组件和服务式组件 无论是使用第三方组件库&#xff0c;还是自己封装组件&#xff0c;有一类组件有些与众不同&#xff0c;那就是函数式/服务式组件&#xff0c;比如 Message 消息组件、Notification 通知组件、Loading 加载组件等等。 以 ElementPlus 组件库为例&#…

.net反序列化新手入门--Json.Net

**01 **Json.net简介 Json.net即Newtonsoft.Json&#xff0c;是.Net中开源的Json序列化和反序列化工具&#xff0c;官方地址&#xff1a;http://www.newtonsoft.com/json。 它虽然不是官方库&#xff0c;但凭借其优秀的性能获得了广大开发者的喜爱。 官网给出的性能比较&…

8大预测分析工具比较

什么是预测分析工具&#xff1f; 预测分析工具融合了人工智能和业务报告。这些工具包括用于从整个企业收集数据的复杂管道&#xff0c;添加统计分析和机器学习层以对未来进行预测&#xff0c;并将这些见解提炼成有用的摘要&#xff0c;以便业务用户可以对此采取行动。 预测的…

day17集合

1.Set集合 1.1Set集合概述和特点【应用】 不可以存储重复元素没有索引,不能使用普通for循环遍历 1.2Set集合的使用【应用】 存储字符串并遍历 public class MySet1 {public static void main(String[] args) {//创建集合对象Set<String> set new TreeSet<>()…

超级详细的几道python题(附答案)含解析、建议收藏

名字&#xff1a;阿玥的小东东 学习&#xff1a;python、正在学习c 主页&#xff1a;阿玥的小东东 目录 判断字符串 a “welcome to my world” 是否包含单词 b “world”&#xff0c;包含返回 True&#xff0c;不包含返回 False。 从 0 开始计数&#xff0c;输出指定字符串…

SSH使用入门

目录 .1 基础配置 1.1 vscode使用 1.2 HOST连接 .2 文件传输 .1 基础配置 1.1 vscode使用 拓展里搜索 然后点击remote里的设置 选择配置 然后填写配置 Hostname是你要ssh的服务器的ip地址 user是你要连接的服务器的用户名 Host可以随便写一个 如果有端口号也要对应修改 …

对于KMP的next数组的新发现,好像我们并不用回溯

目录 前言 发现 总结 博客主页&#xff1a;张栩睿的博客主页 欢迎关注&#xff1a;点赞收藏留言 系列专栏&#xff1a;c语言学习 家人们写博客真的很花时间的&#xff0c;你们的点赞和关注对我真的很重要&#xff0c;希望各位路过的朋友们能多多点赞并关注我&#xff0c;我会…

datax数据导入starrocks表报列数量不匹配错误,问题解决思路

背景在做客户数据导入任务的时候&#xff0c;需要将客户oracle的数据通过datax导入到 starrocks的表中&#xff0c;但是datax的配置文件中SQL查找客户数据的列数和要导入的starrocks表的列数都是相同且对应的&#xff0c;但是导入结果就是报了列数不对等的错误&#xff0c;Erro…

把代码贴进去自动找bug,这个debug神器自动修复仅需几秒

在编写程序时&#xff0c;无论是对于初学者还是对于专业开发人员&#xff0c;都会花费大量时间来调试或修复源代码错误&#xff0c;也就是 Debug。 这个过程繁琐复杂&#xff0c;包括 Bug 复现和 Bug 定位等环节。如果有了自动化的 Debug 程序&#xff0c;就可以显著提高编程实…

网络文件服务器:FileVista 8.9.3 Crack

FileVista 用于自托管文件共享的FileVista文件管理器 在几分钟内将您的网站变成一个网络文件服务器。 在您的网站上与您的客户或员工共享文件。 将您的机密文件存储在您自己的服务器上并对其进行完全控制。使您的用户只需使用 Web 浏览器即可从任何地方安全地访问、上传和组织文…

深度学习入门基础CNN系列——感受野和多输入通道、多输出通道以及批量操作基本概念

本篇文章主要讲解卷积神经网络中的感受野和通道的基本概念&#xff0c;适合于准备入门深度学习的小白&#xff0c;也可以在学完深度学习后将其作为温习。 如果对卷积计算没有概念的可以看本博主的上篇文章深度学习入门基础CNN系列——卷积计算 一、感受野&#xff08;receptive…

基于Java+SpringBoot+Vue+uniapp微信小程序零食商城系统设计和实现

博主介绍&#xff1a;✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…