当前位置: 首页 > news >正文

Vue.js学习笔记(五)抽奖组件封装——转盘抽奖

基于VUE2转盘组件的开发

文章目录

  • 基于VUE2转盘组件的开发
  • 前言
  • 一、开发步骤
    • 1.组件布局
    • 2.布局样式
    • 3.数据准备
  • 二、最后效果
  • 总结


前言

因为之前的转盘功能是图片做的,每次活动更新都要重做UI和前端,为了解决这一问题进行动态配置转盘组件开发,可以减少一些UI和前端的工作量。


一、开发步骤

1.组件布局

 <van-row class="container"><!-- turntableBox 为整个转盘容器,为正方形,大小由里面元素决定 --><van-col span="24" class="turntableBox"><!-- turntableMain 为转盘底座,比里面的内容大,显示为效果图灰色外圈,但不是空心圆 --><div class="turntableMain" :style="`height:${window.innerWidth * 0.8}px;width:${window.innerWidth * 0.8}px;`"><!-- turntable 为转动区域,作用是为了不让外圈一起转动 --><div ref="turntable" class="turntable":style="`height:${window.innerWidth * 0.8}px;width:${window.innerWidth * 0.8}px;`"><!-- Canvas 转盘饼图背景,具体划分多少块由奖项决定 --><Canvas /><!-- prizeBox 奖项,高为饼图的半径,宽为饼图半径里面有多少块就多少分之一 --><div class="prizeBox"><div class="prizeItem" :style="`width:${perPrize.width}px;height:${perPrize.height}px;transform:translateX(-50%) rotate(-${(perPrize.degree * (index + 1)) - (perPrize.degree / 2)}deg);left:calc(50%)`"v-for="(item, index) in activeInfo.prizeList" :key="index"><p class="title">{{ item.name }}</p><p class="describe">{{ item.describe }}</p><img :src="item.img" style="width: 38%;" /></div></div></div><!-- 启动按钮 --><van-image class="go" fit="cover" width="42px" :src="goPointer" @click="go" /></div></van-col><!-- 结果展示列表 --><van-col span="24"><div id="result"></div></van-col></van-row>

2.布局样式

.turntableBox {margin-top: 10%;.turntableMain {margin: 0 auto;position: relative;border: 10px solid #E5E5E5;border-radius: 100%;}.turntable {transition: all 4s;margin: 0 auto;}.go {position: absolute;top: calc(50% - 31px);left: calc(50% - 21px);}.prizeBox {position: absolute;width: 80%;top: 0;left: calc(50% - 40%);.prizeItem {text-align: center;position: absolute;top: 0;overflow: hidden;text-align: center;transform-origin: center bottom;transform: translateX(-50%);color: #2c3e50;p {margin: 0;padding: 0;}.title {font-size: 18px;margin-top: 12px;}.describe {font-size: 14px;line-height: 28px;white-space: break-spaces;}img {margin-top: 6px;}}}
}

3.数据准备

data 代码如下:包含页面功能所需要的变量

  data() {return {window,/** 活动设置 */activeInfo: {/** 中奖概率 */probabilities: {"一等奖": 10,"二等奖": 10,"三等奖": 10,"四等奖": 10,},/** 奖品信息 */prizeList: [{name: '一等奖',describe: '一等奖',img: 'https://img01.yzcdn.cn/vant/cat.jpeg'},{name: '未中奖',describe: '未中奖',img: 'https://img01.yzcdn.cn/vant/cat.jpeg'},{name: '二等奖',describe: '二等奖',img: 'https://img01.yzcdn.cn/vant/cat.jpeg'},{name: '未中奖',describe: '未中奖',img: 'https://img01.yzcdn.cn/vant/cat.jpeg'},{name: '三等奖',describe: '三等奖',img: 'https://img01.yzcdn.cn/vant/cat.jpeg'},{name: '四等奖',describe: '四等奖',img: 'https://img01.yzcdn.cn/vant/cat.jpeg'},]},/** 是否正在执行动画 */isGo: false,/** 执行动画的对象 */oTurntable: '',/** 即将旋转的度数 */randomDeg: 0,/** 上一次旋转的度数 */lastDeg: 0,/** 抽奖次数 */goTimes: 3,/** 奖品图片 */perPrize: {degree: null,width: null,height: null}}} 

created 代码如下:主要处理角度、宽、高

  created() {const params = getAllParams();if (params) {this.params = params;};/** 奖品 */const angle = (360 / this.activeInfo.prizeList.length) / 2; // 对角角度const ratio = Number(Math.sin(angle * (Math.PI * 2 / 360)).toFixed(2)); // 与半径的比率this.perPrize = {degree: (360 / this.activeInfo.prizeList.length),width: Math.floor((window.innerWidth * ratio)) / 2,/** 高度是直径的一半 */height: window.innerWidth * 0.8 / 2}},

mounted 代码如下:获取转盘区域DOM元素,方便后面操作

  mounted() {this.oTurntable = this.$refs.turntable;},

methods 代码如下:主要操作方法

 /** 点击抽奖 */go() {/** 正在抽奖,未结束继续点击无效 */if (!this.isGo && this.goTimes > 0) {/** 获取中奖结果,再根据结果去转动转盘 */const result = this.generatePrize();/** * 获取奖项下标* 奖项名字可能会重复,所以需要找到奖项的所有下标保存到数组里* 根据下标数组随机生成一个数字来决定选择哪个下标成为最终结果的下标*  */const resultIndexArray = this.activeInfo.prizeList.reduce((acc, item, index) => {if (item.name === result) {acc.push(index);}return acc;}, []);const randomResultIndex = Math.floor(Math.random() * resultIndexArray.length);const index = resultIndexArray[randomResultIndex];/** 奖项总和数量 */const length = this.activeInfo.prizeList.length;/** 调用旋转方法 */this.ratating((360 / length * index) + (360 / length / 2), result);}else if (!this.isGo && this.goTimes <= 0) {this.$toast({message: '抱歉,您的抽奖次数用完了',duration: 3000,});}else {this.$toast('请勿重复点击')return}},/** 获取抽奖结果 */generatePrize() {/** 生成一个 0 到 99 之间的随机数 */const randomNum = Math.floor(Math.random() * 100);let cumulativeProbability = 0;/** 如果概率落在奖项范围内 */for (const prize in this.activeInfo.probabilities) {cumulativeProbability += this.activeInfo.probabilities[prize];if (randomNum < cumulativeProbability) {/** 返回中奖内容 */return prize;}}// 默认返回未中奖return "未中奖";},/** 该方法能产生[n,m]之间随机数,决定转盘转多少圈 */getRandom(n, m) {let result = Math.floor(Math.floor(Math.random() * (m - n + 1) + n))return result;},/** 旋转 */ratating(deg, text) {this.goTimes--;this.isGo = true;/** 旋转圈数 */let turnNumber = this.getRandom(3, 6);/** 记录这次要旋转的度数(传来的度数+圈数) */this.randomDeg = deg + 360 * turnNumber;/*上次指针离初始状态的度数 + 上次的度数 + 这次要旋转的度数(这样的目的是为了每次旋转都从原点开始,保证数据准确)*/let realDeg = (360 - this.lastDeg % 360) + this.lastDeg + this.randomDeg;/** 为对象添加执行动画 */this.oTurntable.style.transform = `rotate(${realDeg}deg)`;setTimeout(() => {this.isGo = false;var list = document.getElementById('result');list.innerHTML += /未中奖/.test(text) ? `<p>很遗憾,您${text}!</p>` : `<p>恭喜您,获得${text}!</p>`;/** 把这次度数存储起来,方便下一次获取 */this.lastDeg = realDeg;}, 4000);}

canvas 组件代码如下:主要使用canvas标签根据奖项长度进行角度划分绘画,


<template><canvas class="canvas" id="canvasImg" :style="`width:${perimeter}px;height: ${perimeter}px;`">您的浏览器不支持canvas!</canvas>
</template><script>export default {name: 'Canvas',components: {},data() {return {/** 直径 */perimeter: 320,}},created() {},mounted() {this.perimeter = window.innerWidth * 0.8;this.drawPie();},methods: {/** 画饼图 */drawPie() {const PI = Math.PI;/** 获取画布并获取2d上下文对象 */const canvas = document.getElementById('canvasImg');const ctx = canvas.getContext('2d');/** 假设周长为500 */const perimeter = this.perimeter;/** 半径 */const radius = perimeter * 0.5;/** 总奖品数,需要根据实际数据长度从父组件传入 */const prizeTotal = 6;/** 每个扇形的角度=360度 / 总奖品数 */const degree = 360 / prizeTotal;/** 画布宽高 */canvas.width = perimeter;canvas.height = perimeter;/** 根据奖品数把圆形分成等份的扇形 */for (let i = 0; i < prizeTotal; i++) {/** 奇偶颜色 */const color = i % 2 === 0 ? "#F8D383" : "#F8E2BC";/** 开始一条新路径 */ctx.beginPath();/** 设置路径起点 */ctx.moveTo(radius, radius);/** 填充颜色 */ ctx.fillStyle = color;/** 绘制扇形 (圆心坐标,圆心坐标,半径,扇形起始角度,扇形终止角度) */ctx.arc(radius, radius, radius, (270 - degree  + (degree * i)) * PI / 180, (270 - degree  + degree + (degree * i)) * PI / 180);/** 自动绘制一条当前点到起点的直线,形成一个封闭图形,省却使用一次moveTo方法。 */ctx.closePath();/** 闭合路径 */ctx.fill();}}},
}
</script><style lang="less"></style>

二、最后效果

在这里插入图片描述


总结

本文仅仅简单记录了转盘组件的基本实现,仅供学习参考。

相关文章:

Vue.js学习笔记(五)抽奖组件封装——转盘抽奖

基于VUE2转盘组件的开发 文章目录 基于VUE2转盘组件的开发前言一、开发步骤1.组件布局2.布局样式3.数据准备 二、最后效果总结 前言 因为之前的转盘功能是图片做的&#xff0c;每次活动更新都要重做UI和前端&#xff0c;为了解决这一问题进行动态配置转盘组件开发&#xff0c;…...

使用pip或conda离线下载安装包,使用pip或conda安装离线安装包

使用pip或conda离线下载安装包&#xff0c;使用pip或conda安装离线安装包 一、使用pip离线下载安装包1. 在有网络的机器上下载包和依赖2. 传输离线安装包 二、在目标机器上离线安装pip包三、使用conda离线下载安装包1. 在有网络的机器上下载conda包2. 传输conda包或环境包3. 在…...

产品访问分析

1、DWD产品访问明细 1.1、用户产品权限数据 --用户产品权限数据INSERT OVERWRITE TABLE temp_lms.dm_lms_platform_usergroup_app_tmpselect 仓储司南 as pro_name,CCSN as pro_code,c.user_name as user_name,d.account_name …...

【算法】代码随想录之链表(更新中)

文章目录 前言 一、移除链表元素&#xff08;LeetCode--203&#xff09; 前言 跟随代码随想录&#xff0c;学习链表相关的算法题目&#xff0c;记录学习过程中的tips。 一、移除链表元素&#xff08;LeetCode--203&#xff09; 【1】题目描述&#xff1a; 【2】解决思想&am…...

react 18中,使用useRef 获取其他组件的dom并操作节点,flushSync强制同步更新useState

React 不允许组件访问其他组件的 DOM 节点。甚至自己的子组件也不行&#xff01;这是故意的。Refs 是一种脱围机制&#xff0c;应该谨慎使用。手动操作 另一个 组件的 DOM 节点会使你的代码更加脆弱。 相反&#xff0c;想要 暴露其 DOM 节点的组件必须选择该行为。一个组件可以…...

Jupyter Notebook基础:用IPython实现动态编程

Jupyter Notebook基础&#xff1a;用IPython实现动态编程 1. 引言 Jupyter Notebook是一个基于Web的交互式计算环境&#xff0c;允许用户创建和共享包含实时代码、方程式、可视化和文本叙述的文档。它广泛应用于数据清洗与转换、数值模拟、统计建模、机器学习以及其他数据科学…...

Python 爬虫:使用打码平台来识别各种验证码:

本课程使用的是 超级鹰 打码平台&#xff0c; 没有账户的请自行注册&#xff01; 超级鹰验证码识别-专业的验证码云端识别服务,让验证码识别更快速、更准确、更强大 使用打码平台来攻破验证码难题&#xff0c; 是很简单容易的&#xff0c; 但是要钱&#xff01; 案例代码及测…...

理解算法复杂度:空间复杂度详解

引言 在计算机科学中&#xff0c;算法复杂度是衡量算法效率的重要指标。时间复杂度和空间复杂度是算法复杂度的两个主要方面。在这篇博客中&#xff0c;我们将深入探讨空间复杂度&#xff0c;了解其定义、常见类型以及如何进行分析。空间复杂度是衡量算法在执行过程中所需内存…...

浅析Kafka Streams消息流式处理流程及原理

以下结合案例&#xff1a;统计消息中单词出现次数&#xff0c;来测试并说明kafka消息流式处理的执行流程 Maven依赖 <dependencies><dependency><groupId>org.apache.kafka</groupId><artifactId>kafka-streams</artifactId><exclusio…...

QGroundControl的总体架构,模块化设计和主要组件的功能。

QGroundControl 总体架构详细描述 QGroundControl (QGC) 作为一个开源地面控制站软件&#xff0c;其设计原则是模块化、高扩展性和高可维护性。 总体架构 QGroundControl 由多个层次构成&#xff0c;每个层次负责不同的功能。这种分层结构确保了系统的高内聚性和低耦合性。 …...

oracle 表空间文件迁移

表空间文件迁移 背景 由于各种原因&#xff0c;在实际工作中可能会出现oracle服务器数据盘空间被占满的情况&#xff0c;这个时候单纯的添加新磁盘&#xff0c;后续表空间文件放新盘的方案已经不适用了&#xff0c;因为源盘已经占用满了&#xff0c;数据库服务会异常&#xf…...

JVM学习(day1)

JVM 运行时数据区 线程共享&#xff1a;方法区、堆 线程独享&#xff08;与个体“同生共死”&#xff09;&#xff1a;虚拟机栈、本地方法栈、程序计数器 程序计数器 作用&#xff1a;记录下次要执行的代码行的行号 特点&#xff1a;为一个没有OOM&#xff08;内存溢出&a…...

js项目生产环境中移除 console

1、terser-webpack-plugin webpack 构建的项目中安装使用 安装&#xff1a; npm install terser-webpack-plugin --save-dev 配置 在webpack.config.js文件中 new TerserPlugin({terserOptions: {output: {comments: false, // 去除注释},warnings: false, // 去除黄色警告,co…...

ROS2 + 科大讯飞 初步实现机器人语音控制

环境配置&#xff1a; 电脑端&#xff1a; ubuntu22.04实体机作为上位机 ROS版本&#xff1a;ros2-humble 实体机器人&#xff1a; STM32 思岚A1激光雷达 科大讯飞语音SDK 讯飞开放平台-以语音交互为核心的人工智能开放平台 实现步骤&#xff1a; 1. 下载和处理科大讯飞语音模…...

HTML5新增的input元素属性:placeholder、required、autofocus、min、max等

HTML5 大幅度地增加与改良了 input 元素的属性&#xff0c;可以简单地使用这些属性来实现 HTML5 之前需要使用 JavaScript 才能实现的许多功能。 下面将详细介绍这些新增的 input 元素的属性。 属性说明属性说明placeholder在输入框显示描述性或提示性文本autocomplete是否保…...

Cornerstone3D导致浏览器崩溃的踩坑记录

WebGL: CONTEXT_LOST_WEBGL: loseContext: context lost ⛳️ 问题描述 在使用vue3vite重构Cornerstone相关项目后&#xff0c;在Mac本地运行良好&#xff0c;但是部署测试环境后&#xff0c;在window系统的Chrome浏览器中切换页面会导致页面崩溃。查看Chrome的任务管理器&am…...

【鸿蒙学习笔记】Stage模型

官方文档&#xff1a;Stage模型开发概述 目录标题 Stage模型好处Stage模型概念图ContextAbilityStageUIAbility组件和ExtensionAbility组件WindowStage Stage模型-组件模型Stage模型-进程模型Stage模型-ArkTS线程模型和任务模型关于任务模型&#xff0c;我们先来了解一下什么是…...

Docker进入MongoDB

先是命令行开启docker镜像&#xff0c;然后进入docker镜像&#xff0c;这是两步 进入之后&#xff0c;开头会变成root&#xff0c;我的理解是进入了另一个linux系统了&#xff0c;直接执行相应的软件 这里直接use databse就是进入了&#xff0c;据说MongoDB是慢启动&#xff0c…...

APP与API:魔法世界的咒语与念咒者

1. 什么是API&#xff1f; API&#xff0c;即应用程序编程接口&#xff08;Application Programming Interface&#xff09;&#xff0c;就像是魔法世界中的咒语。API是两个独立软件系统之间进行通信和数据交换的桥梁。通过API&#xff0c;一个软件系统可以调用另一个软件系统中…...

云计算安全需求分析与安全保护工程

云计算基本概念 云计算&#xff08;Cloud Computing&#xff09;是一种通过互联网提供计算资源和服务的技术。它允许用户按需访问和使用计算资源&#xff0c;如服务器、存储、数据库、网络、安全、分析和软件应用等&#xff0c;而无需管理底层基础设施。以下是云计算的基本概念…...

2026年京东云OpenClaw/Hermes Agent配置Token Plan环境搭建指南

2026年京东云OpenClaw/Hermes Agent配置Token Plan环境搭建指南。OpenClaw是开源的个人AI助手&#xff0c;Hermes Agent则是一个能自我进化的AI智能体框架。阿里云提供计算巢、轻量服务器及无影云电脑三种部署OpenClaw 与 Hermes Agent的方案、百炼Token Plan兼容主流 AI 工具&…...

Vue.js 版本全解析与 nvm 环境管理完全指南

前言&#xff1a;为什么需要了解这些&#xff1f;在前端开发的世界里&#xff0c;Vue.js 已经成为最受欢迎的框架之一。但在实际工作中&#xff0c;我们常常会面临两个问题&#xff1a;项目 A 需要用 Vue 2&#xff08;为了兼容 IE11&#xff09;&#xff0c;项目 B 想用 Vue 3…...

taotoken如何帮助初创团队以可控成本快速验证ai产品创意

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 Taotoken如何帮助初创团队以可控成本快速验证AI产品创意 1. 初创团队验证AI创意的核心挑战 对于初创团队而言&#xff0c;验证一个…...

从一颗2N5551看懂半导体散热:热阻Rja、Rjc到底怎么测?对我们选型有啥用?

从一颗2N5551看懂半导体散热&#xff1a;热阻Rja、Rjc到底怎么测&#xff1f;对我们选型有啥用&#xff1f; 拆开一颗塑料封装的2N5551三极管&#xff0c;你会看到指甲盖大小的黑色环氧树脂包裹着不到1平方毫米的硅晶片。这个微型结构在工作时产生的热量&#xff0c;可能让芯片…...

TegraRcmGUI终极指南:Windows上最简单的Switch注入工具免费使用教程

TegraRcmGUI终极指南&#xff1a;Windows上最简单的Switch注入工具免费使用教程 【免费下载链接】TegraRcmGUI C GUI for TegraRcmSmash (Fuse Gele exploit for Nintendo Switch) 项目地址: https://gitcode.com/gh_mirrors/te/TegraRcmGUI TegraRcmGUI是一款专为Windo…...

终极指南:免费实现Zwift离线骑行模拟的完整方案

终极指南&#xff1a;免费实现Zwift离线骑行模拟的完整方案 【免费下载链接】zwift-offline Use Zwift offline 项目地址: https://gitcode.com/gh_mirrors/zw/zwift-offline 想要在没有网络连接的情况下享受Zwift专业骑行训练吗&#xff1f;Zwift-Offline开源项目为你提…...

如何在Linux上安装Realtek R8125 2.5GbE网卡驱动:完整指南

如何在Linux上安装Realtek R8125 2.5GbE网卡驱动&#xff1a;完整指南 【免费下载链接】realtek-r8125-dkms A DKMS package for easy use of Realtek r8125 driver, which supports 2.5 GbE. 项目地址: https://gitcode.com/gh_mirrors/re/realtek-r8125-dkms 你是否正…...

3分钟搞定百度网盘提取码:新手也能快速上手的终极解决方案

3分钟搞定百度网盘提取码&#xff1a;新手也能快速上手的终极解决方案 【免费下载链接】baidupankey 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 你是否经常遇到这样的烦恼&#xff1a;朋友分享的百度网盘链接明明就在眼前&#xff0c;却因为缺少那个关…...

向量数据库是什么?Milvus 与 ChromaDB 在 AI 测试中的作用

导语:2025年,AI应用开发圈最火的两个关键词——RAG(检索增强生成)和向量数据库。你可能已经用LangChain搭过聊天机器人,用LlamaIndex建过知识库,但你有没有认真想过:那个默默躺在你架构图最底层的向量数据库,到底该选谁?Milvus还是ChromaDB?它们到底有什么区别?对你…...

JMeter gRPC性能测试解决方案:微服务协议性能验证技术实现

JMeter gRPC性能测试解决方案&#xff1a;微服务协议性能验证技术实现 【免费下载链接】jmeter-grpc-request JMeter gRPC Request load test plugin for gRPC 项目地址: https://gitcode.com/gh_mirrors/jm/jmeter-grpc-request 随着微服务架构的普及&#xff0c;gRPC已…...