前端实现转盘抽奖 - 使用 lucky-canvas 插件
目录
- 需求背景
- 需求实现
- 实现过程图片示意
- 实现代码
- 页面效果
- lucky-canvas 插件官方文档
需求背景
要求实现转盘转动抽奖的功能:
- 只有正确率大于等于 80% 才可以进行抽奖;
- “谢谢参与”概率为 90%,“恭喜中奖”概率为 10%;
需求实现


实现过程图片示意

实现代码
安装插件
npm install @lucky-canvas/vue@latest
main.js 全局引入组件
import VueLuckyCanvas from '@lucky-canvas/vue'
Vue.use(VueLuckyCanvas)
实现代码
<template><div class="exam-result"><div class="info"><div class="progress"><nut-circleprogress:progress="(correct / total).toFixed(1) * 100":is-auto="true"color="#ff4d4f"path-color="#ffeded"><div class="progressDiv"><div class="accuracy">正确率{{ (correct / total).toFixed(1) * 100 }}%</div></div></nut-circleprogress></div></div><div class="content"><div class="result-table"><div style="padding: 10px 10px 10px 15px">试卷分析</div></div><div class="result-table"><div class="item"><div class="title">题目总量:</div><div class="total">{{ total }}</div><div class="unit">题</div></div></div><div class="result-table"><div class="item"><div class="title">正确题数:</div><div class="correct">{{ correct }}</div><div class="unit">题</div></div><div class="item"><div class="title">错误题数:</div><div class="error">{{ total - correct }}</div><div class="unit">题</div></div></div></div><div v-if="examType === 'challenge' && (correct / total).toFixed(1) >= 0.8" class="lottery_draw_btn">恭喜您获得抽奖资格 <nut-button type="primary" size="mini" @click="toLotteryDraw">点击进行抽奖</nut-button></div><nut-dialog teleport="#app" :title="isShowlotteryDraw ? '点击“开始”抽奖' : ''" content="" v-model:visible="dialogVisible" customClass="task" :noCancelBtn="true" :noOkBtn="true" :closeOnClickOverlay="false"><nut-icon name="close" @click="dialogVisible = false" /><LuckyWheelv-if="isShowlotteryDraw"class="myLucky"ref="myLuckyRef"width="320px"height="320px":prizes="prizes":blocks="blocks":buttons="buttons"@start="startCallback"@end="endCallback"/><div v-else class="result" :style="{'--color': lotteryDrawIndex === 1 ? 'red' : '#000'}">{{ lotteryDrawIndex === 1 ? "恭喜中奖" : "谢谢参与" }}</div></nut-dialog></div><fallback></fallback>
</template><script>
import {reactive, toRefs, ref, getCurrentInstance
} from 'vue'
import { useRoute } from 'vue-router'export default {name: 'result',setup() {// const myLuckyRef = ref(null) // 【ref问题】我的代码里这种办法取不到 ref,使用 getCurrentInstance 取 refconst instance = getCurrentInstance() // 【ref解决】使用 getCurrentInstance 取 refconst route = useRoute()const state = reactive({lotteryDrawIndex: 0, // 最终转盘定格的索引isShowlotteryDraw: true, // 是否抽奖完成// 转盘背景配置blocks: [{padding: '20px',imgs: [{// src: 'https://img.iwave.net.cn/jeep/51c95637a377c3a12d09abe8b0f975e6.png',src: require('@/assets/images/lottery_draw.png'),width: 320,height: 320,rotate: true}]}],// 每个扇形区域奖品配置prizes: [...Array(10).keys()].map((index) => ({fonts: [{text: index % 2 === 0 ? '谢谢参与' : '恭喜中奖',top: '15%',fontSize: '15px',fontColor: '#ed1c24',},],background: index % 2 === 0 ? '#fff5cc' : '#e9d6e9',})),// 抽奖按钮配置buttons: [{ radius: '50px', background: '#d034ac' },{ radius: '45px', background: '#fe97b2' },{radius: '35px',background: '#f04a07',pointer: true,fonts: [{ text: '开始', top: '-10px', fontColor: '#fff' }]}],// 抽奖弹框是否展示dialogVisible: false})// 获取正确题数、总题数const { correct, total, examType } = route.queryconst toLotteryDraw = () => {state.dialogVisible = true}// 点击抽奖按钮会触发star回调const startCallback = () => {console.log('"开始抽奖"----', '开始抽奖')// 调用抽奖组件的play方法开始游戏// console.log('myLucky.value----', myLuckyRef.value) // 【ref问题】// myLuckyRef.value?.play() // 【ref问题】if (instance) {instance.refs?.myLuckyRef?.play() // 【ref解决】}// this.$refs.myLucky.play() // 【ref】vue2写法// 模拟调用接口异步抽奖setTimeout(() => {// 假设index(谢谢参与90%,恭喜中奖10%)const index = `${Math.random()}`.slice(2, 3) * 1state.lotteryDrawIndex = index === 1 ? 1 : 2// 调用stop停止旋转并传递中奖索引// this.$refs.myLuckyRef.stop(index) // 【ref】vue2写法// myLuckyRef.value?.stop(index) // 【ref问题】if (instance) {instance.refs?.myLuckyRef?.stop(state.lotteryDrawIndex) // 【ref解决】}}, 3000)}// 抽奖结束会触发end回调const endCallback = (prize) => {console.log('"结束抽奖"----', '结束抽奖')console.log(prize)state.isShowlotteryDraw = false}return {...toRefs(state),correct,total,examType,toLotteryDraw,startCallback,endCallback}}
}
</script><style scoped lang="less">
.exam-result {.info {margin: 0 0 5px;padding: 10px;background-color: white;.progress {display: flex;flex-direction: column;align-items: center;padding: 5px;position: relative;.nut-circleprogress {width: 145px !important;height: 145px !important;position: relative;.progressDiv {display: flex;flex-direction: column;align-items: center;.accuracy {color: #00000080;background-color: #ffeded;padding: 2px 8px;font-size: 13px;border-radius: 5px;}}}.circle {position: absolute;height: 145px;width: 145px;background-color: #ffeded;border-radius: 50%;top: 5px;left: 50%;transform: translate(-50%);.circle1 {position: absolute;height: 115px;width: 115px;background-color: #ffffff;border-radius: 50%;top: 50%;left: 50%;transform: translate(-50%, -50%);}}}.count {background-color: #fffbf3;margin-top: 10px;padding-top: 5px;color: #797e79;font-size: 14px;display: flex;justify-content: space-around;.centerDiv {display: flex;align-items: baseline;justify-content: center;.number {margin-right: 5px;font-size: 20px;color: #FAAD14;}.text {font-size: 12px;}}}}.content {margin-bottom: 10px;background: white;border-bottom: 1px solid #dcdcdc;.result-table {display: flex;font-size: 16px;font-weight: bolder;color: #000;.item {display: flex;align-items: baseline;border-top: 0.5px solid #dcdcdc;flex: 1;font-size: 16px;padding: 10px 10px 10px 15px;color: #7f7f7f;font-weight: normal;&:nth-child(2n+1) {border-right: 0.5px solid #dcdcdc;}.title {margin-right: 5px;font-size: 14px;}.unit {font-size: 12px;margin-left: 5px;}.time,.total {color: black;font-size: 16px;}.correct {color: #04be01;font-size: 18px;}.error {color: red;font-size: 18px;}}}}// 弹框样式::v-deep .popup-center.round {width: 90%;.nut-dialog {width: 100%;padding: 20px 5px;.nut-dialog__content {max-height: unset;.nut-icon-close {position: absolute;top: 15px;right: 15px;}// 转盘结束展示结果.result {height: 80px;line-height: 80px;font-size: 20px;font-weight: bold;color: var(--color);}// 转盘.myLucky {display: inline-block;}}}}// 抽奖弹框按钮.lottery_draw_btn {height: 25PX;line-height: 25PX;padding: 0 10px;cursor: pointer;font-size: 16px;color: red;}
}
</style>
页面效果


lucky-canvas 插件官方文档
lucky-canvas 插件官网
lucky-canvas 插件官网文档
可参考文档
相关文章:
前端实现转盘抽奖 - 使用 lucky-canvas 插件
目录 需求背景需求实现实现过程图片示意实现代码 页面效果lucky-canvas 插件官方文档 需求背景 要求实现转盘转动抽奖的功能: 只有正确率大于等于 80% 才可以进行抽奖;“谢谢参与”概率为 90%,“恭喜中奖”概率为 10%; 需求实现 实…...
2024.1.23力扣每日一题——最长交替子数组
2024.1.23 题目来源我的题解方法一 枚举 题目来源 力扣每日一题;题序:2765 我的题解 方法一 枚举 每次都以两个相邻作为满足要求的循环数据,并且以一个布尔变量控制循环的位置 时间复杂度:O(n) 空间复杂度:O(1) pub…...
C语言王道练习题第七周两题
第一题 Description 输入一个学生的学号,姓名,性别,用结构体存储,通过 scanf 读取后,然后再 通过 printf 打印输出 Input 学号,姓名,性别,例如输入 101 xiongda m Output 输出…...
某马头条——day11+day12
实时计算和定时计算 流式计算 kafkaStream 入门案例 导入依赖 <dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-streams</artifactId><exclusions><exclusion><artifactId>connect-json</artifactId&…...
springboot实现aop
目录 AOP(术语)引入依赖实现步骤测试验证感谢阅读 AOP(术语) 连接点 类里面哪些方法可以增强,这些点被称为连接点 切入点 实际被真正增强的方法 通知(增强) 实际增强的逻辑部分称为通知(增强) 通知(增强&…...
Golang 中高级工程师学习笔记
闭包的作用 闭包(Closure)是一种函数值,它可以引用在其外部定义的变量。闭包允许这些变量保持在函数内部,而不是被每次调用时重新创建。闭包的作用主要体现在以下几个方面 封装: 闭包允许函数访问其外部作用域中的变…...
USB-C接口给显示器带来怎样的变化?
随着科技的不断发展,Type-C接口已经成为现代电子设备中常见的接口标准。它不仅可以提供高速的数据传输,还可以实现快速充电和视频传输等功能。因此,使用Type-C接口的显示器方案也受到了广泛的关注。本文将介绍Type-C接口显示器的优势、应用场…...
写一份简单的产品说明书:格式和排版建议
现在的市场竞争那么激烈,拥有一份简洁明了的产品说明书可以说是很重要的。产品说明书不仅向用户提供了对产品的详细了解,还能够树立品牌形象,提升用户体验。 | 一、写一份简单的产品说明书—一些建议 1.创意封面设计 一个吸引人的封面设计能…...
【Python学习】Python学习21- 正则表达式(1)
目录 【Python学习】Python学习21- 正则表达式(1) 前言re.match函数实例 re.search方法re.match与re.search的区别参考 文章所属专区 Python学习 前言 本章节主要说明Python的正则表达式。 正则表达式是一个特殊的字符序列,它能帮助你方便的…...
Docker 和 Kubernetes:容器化时代的崛起与演变
在过去的十年间,容器化技术彻底改变了软件开发和部署的面貌。 Docker 的登场无疑是这场变革的催化剂,它将应用和服务的打包、分发、部署流程标准化,让开发者的生活变得更加简单。 紧随其后,Kubernetes 作为容器编排的领军者&#…...
美易官方京东养车回应索赔事件:推动行业健康发展并携手品牌商家加码补贴
近日,一则关于途虎养车起诉京东索赔500万元的新闻引起了业界的广泛关注。据华尔街见闻1月25日报道,针对此事,京东养车相关负责人作出了回应。京东养车表示,“震虎价”并非针对特定企业,其核心目的在于通过提升效率来改…...
深度学习与图像描述生成——看图说话(3)
目录 一、整体架构 二、学习策略 2.1 监督学习 2.2 无监督学习 2.3 强化学习 三、特征映射 3.1 定义 3.2 原理 3.3 关键技术 3.4 重要案例 3.5 特别注意下特征空间这一概念 四、语言模型 4.1 定义与原理 4.2 关键技术 4.3 重要性与作用 4.4 案例与应用 五、注…...
[SAP ABAP] ABAP编程中SY-SUBRC值的含义
在ABAP编程中,SY-SUBRC是一个系统变量,用于表示最近一次执行的系统命令(例如数据库操作、函数模块调用等)的结果状态码 SY-SUBRC的值用于检查命令是否执行成功,通常用于控制程序的流程 查询数据 使用SELECT语句选择查询 SY-SUBRC 0 &qu…...
测试模型分类
测试模型 1. 概述 软件测试和软件开发一样,都遵循软件工程原理,遵循管理学原理,所以理解好软件的开发模型会便于理解测试模型. 软件测试的一般流程: 我们发现一般的软件测试流程和软件开发的流程一样,但是这样的流程测试介入的较晚,对于前期重大的bug很难修复.所以测试的流程…...
mavros和PX4中的海拔高与椭球高转换
飞控高度传感器中一般有两种高度: 海拔高。也称AMSL(Above Mean Sea Level)height或者geoid height或者正高,顾名思义就是指高于当地平均海平面的高度。我猜气压计测得的高度应当就是与海平面相关的。椭球高。也称ellipsoid heig…...
洛谷刷题-【入门2】分支结构
目录 1.苹果和虫子 题目描述 输入格式 输出格式 输入输出样例 2.数的性质 题目描述 输入格式 输出格式 输入输出样例 3.闰年判断 题目描述 输入格式 输出格式 输入输出样例 4.apples 题目描述 输入格式 输出格式 输入输出样例 5.洛谷团队系统 题目描述 …...
文件包含技术总结
开发人员一般会把重复使用的函数写到单个文件中,需要使用某个函数时直接调用此文件,而无需再次编写,这中文件调用的过程一般被称为文件包含。 allow_url_fopen On(是否允许打开远程文件) allow_url_include On&…...
Docker搭建私有仓库
Docker搭建私有仓库 下载docker registry镜像 docker pull docker.io/registry2.registry镜像下载完成后,先创建一个存放镜像的目录。 mkdir -p /data/registry3.启动registry容器 docker run -itd -p 5000:5000 -v /data/registry:/var/lib/registry docker.io…...
【计算机网络】【练习题】【新加坡南洋理工大学】【Computer Control Network】
说明: 仅供学习使用。 一、题目描述 该题目描述一个网络中传播时延(Transmission Delay)的例子。题目如下: 二、问题解答(个人) 笔者第3问采用均值不等式求解。标答中采用求导数的方法求极值。似乎均值…...
【学习笔记】CF1349F2 Slime and Sequences (Hard Version)
多项式工业警告!!! 点击看题意 思路来自 这位大佬 。 为什么这么好的题解没人评论。 Part 1 前置知识:拉格朗日反演(多项式复合),分式域(引入负整数次项)。 条件&a…...
观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...
如何在Windows本机安装Python并确保与Python.NET兼容
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...
倒装芯片凸点成型工艺
UBM(Under Bump Metallization)与Bump(焊球)形成工艺流程。我们可以将整张流程图分为三大阶段来理解: 🔧 一、UBM(Under Bump Metallization)工艺流程(黄色区域ÿ…...
Spring AOP代理对象生成原理
代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】,这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...
