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

使用 Vue 和 Canvas-Confetti 实现烟花动画特效

在开发中,为用户提供具有视觉冲击力的反馈是一种提升用户体验的好方法。今天,我们将结合 Vue 框架、canvas-confetti 和 Lottie 动画,创建一个动态对话框动画,其中包含炫酷的烟花特效。

效果图:

效果简介

当用户触发特定事件时:

  1. 弹出一个对话框,加载基于用户等级的 Lottie 动画。
  2. 配合对话框的展示,启动烟花特效(canvas-confetti),模拟庆祝场景。
  3. 用户关闭对话框时,清除动画和特效。

使用的技术栈

  • Vue 3: 构建响应式用户界面。
  • Lottie: 显示矢量动画,支持用户等级的动态变化。
  • canvas-confetti: 用于生成烟花效果,支持细粒度的控制和动画定制。

实现步骤

1. 安装依赖
npm install canvas-confetti lottie-web

2. 代码实现

以下是核心代码的分步解析:

初始化状态和依赖
import confetti from 'canvas-confetti'
import lottie from 'lottie-web'
import { watchEffect, computed, ref } from 'vue'
import { useGlobalStore } from '@/stores/global'
import { useUserStore } from '@/stores/user'

  • 引入 canvas-confettilottie-web
  • 使用 useGlobalStoreuseUserStore 来获取全局状态和用户数据。

动态动画加载

通过 watchEffect 监听对话框状态,动态加载 Lottie 动画和烟花效果:

 
watchEffect(() => {if (value.value) {// 加载 Lottie 动画animation = lottie.loadAnimation({container: animationContainer.value,renderer: 'svg',loop: true,autoplay: true,animationData: getLottieFileByUserLevel(),})// Lottie 动画加载完成后触发烟花效果animation.addEventListener('DOMLoaded', startConfetti)} else {// 清除动画和烟花if (animation) {animation.destroy()animation = null}if (animationFrameId) {cancelAnimationFrame(animationFrameId)animationFrameId = null}}
})


创建烟花效果

通过 requestAnimationFrame 控制粒子效果的动态生成:

const startConfetti = () => {const duration = 15 * 1000 // 烟花持续时间const defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 2100 }const animationEnd = Date.now() + durationconst frame = () => {const timeLeft = animationEnd - Date.now()if (timeLeft <= 0) {if (animationFrameId) cancelAnimationFrame(animationFrameId)return}const particleCount = 10 * (timeLeft / duration)confetti({...defaults,particleCount,origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 },})confetti({...defaults,particleCount,origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 },})// 循环调用animationFrameId = requestAnimationFrame(frame)}frame()
}

这里的 randomInRange 函数用来随机生成粒子发射的方向和范围:

function randomInRange(min: number, max: number) {return Math.random() * (max - min) + min
}


根据用户等级加载 Lottie 动画

不同的用户等级对应不同的动画文件:

const getLottieFileByUserLevel = () => {let level = userStore.userLevelif (level === 2) {return Level02Lottie} else if (level === 3) {return Level03Lottie} else if (level === 4) {return Level04Lottie} else if (level === 5) {return Level05Lottie} else if (level === 6) {return Level06Lottie} else {return Level01Lottie}
}


3. 完整代码
<script lang="ts" setup>
import confetti from 'canvas-confetti'
import { watchEffect, computed, ref } from 'vue'
import { useGlobalStore } from '@/stores/global'
import { useUserStore } from '@/stores/user'
import lottie from 'lottie-web'
import Level01Lottie from '@/assets/lottie/Level01.json'
import Level02Lottie from '@/assets/lottie/Level02.json'
import Level03Lottie from '@/assets/lottie/Level03.json'
import Level04Lottie from '@/assets/lottie/Level04.json'
import Level05Lottie from '@/assets/lottie/Level05.json'
import Level06Lottie from '@/assets/lottie/Level06.json'const globalStore = useGlobalStore()
const userStore = useUserStore()
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
const animationContainer = ref()
let animation: any = null
let animationFrameId: number | null = nullconst value = computed({get() {return props.modelValue},set(value) {emit('update:modelValue', value)},
})const beforeClose = () => {globalStore.fireworkVisable.show = false
}// Confetti effect function with requestAnimationFrame
function randomInRange(min: number, max: number) {return Math.random() * (max - min) + min
}const getLottieFileByUserLevel = () => {let level = userStore.userLevelif (level === 2) {return Level02Lottie} else if (level === 3) {return Level03Lottie} else if (level === 4) {return Level04Lottie} else if (level === 5) {return Level05Lottie} else if (level === 6) {return Level06Lottie} else {return Level01Lottie}
}const startConfetti = () => {const duration = 15 * 1000const defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 2100 }const animationEnd = Date.now() + durationconst frame = () => {const timeLeft = animationEnd - Date.now()if (timeLeft <= 0) {if (animationFrameId) cancelAnimationFrame(animationFrameId)return}const particleCount = 10 * (timeLeft / duration)confetti({...defaults,particleCount,origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 },})confetti({...defaults,particleCount,origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 },})// Continue the animation loopanimationFrameId = requestAnimationFrame(frame)}frame()
}watchEffect(() => {if (value.value) {// Load lottie animationanimation = lottie.loadAnimation({container: animationContainer.value,renderer: 'svg',loop: true,autoplay: true,animationData: getLottieFileByUserLevel(),})// Start confetti after lottie loadsanimation.addEventListener('DOMLoaded', startConfetti)} else {// Destroy lottie animation and cancel confetti animationif (animation) {animation.destroy()animation = null}if (animationFrameId) {cancelAnimationFrame(animationFrameId)animationFrameId = null}}
})
</script><template><div class="tipBox"><el-dialog v-model="value" title="" :before-close="beforeClose"><div ref="animationContainer" style="width: 100%; height: 100%"></div></el-dialog></div>
</template><style lang="scss" src="./style.scss" scoped />

 


总结

以上实现为用户提供了动态且炫酷的视觉体验:

  1. 对话框弹出时加载用户特定的动画。
  2. 使用 canvas-confetti 模拟烟花特效,持续 15 秒。
  3. 对话框关闭时清理资源,避免性能问题。

这种效果非常适用于用户晋级、任务完成等场景,希望本文能对你有所启发!

相关文章:

使用 Vue 和 Canvas-Confetti 实现烟花动画特效

在开发中&#xff0c;为用户提供具有视觉冲击力的反馈是一种提升用户体验的好方法。今天&#xff0c;我们将结合 Vue 框架、canvas-confetti 和 Lottie 动画&#xff0c;创建一个动态对话框动画&#xff0c;其中包含炫酷的烟花特效。 效果图&#xff1a; 效果简介 当用户触发…...

【银河麒麟操作系统真实案例分享】内存黑洞导致服务器卡死分析全过程

了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer.kylinos.cn 文档中心&#xff1a;https://documentkylinos.cn 现象描述 机房显示器连接服务器后黑屏&#xff…...

如何加强游戏安全,防止定制外挂影响游戏公平性

在现如今的游戏环境中&#xff0c;外挂始终是一个困扰玩家和开发者的问题。尤其是定制挂&#xff08;Customized Cheats&#xff09;&#xff0c;它不仅复杂且隐蔽&#xff0c;更能针对性地绕过传统的反作弊系统&#xff0c;对游戏安全带来极大威胁。定制挂通常是根据玩家的需求…...

SpringBoot整合knife4j,以及会遇到的一些bug

这篇文章主要讲解了“Spring Boot集成接口管理工具Knife4j怎么用”&#xff0c;文中的讲解内容简单清晰&#xff0c;易于学习与理解&#xff0c;下面请大家跟着小编的思路慢慢深入&#xff0c;一起来研究和学习“Spring Boot集成接口管理工具Knife4j怎么用”吧&#xff01; 一…...

城电科技|光伏廊道是什么?安装光伏廊道有什么好处?

光伏廊道是什么&#xff1f;光伏廊道专门设计用于集中安装太阳能光伏发电系统的建筑物或构筑物&#xff0c;它可以将光伏转换成可以用于供电的清洁绿电。光伏廊道通常由阳能电池板、太阳能电池、控制器、逆变器、混凝土、钢材等材料组成&#xff0c;具备发电、坚固、耐用、防水…...

当DHCP服务器分配了同一个IP地址

当DHCP服务器分配了同一个IP地址给多个设备时&#xff0c;这通常会导致网络问题&#xff0c;如IP地址冲突&#xff0c;进而影响设备的网络连接。以下是详细的分析和解决步骤&#xff1a; 原因分析&#xff1a; IP地址租约未过期&#xff1a; 租约管理&#xff1a;DHCP服务器维…...

储能能量自动化调配装置功能介绍

随着可再生能源的快速发展&#xff0c;光伏发电已成为全球能源结构转型的关键技术之一。与此同时&#xff0c;储能技术作为实现光伏发电稳定输出的核心技术&#xff0c;得到了广泛关注。在企业电网中&#xff0c;光伏储能系统的运维管理不仅关乎能源利用效率&#xff0c;还涉及…...

vite5+vue3+Ts5 开源图片预览器上线

images-viewer-vue3&#xff1a;一款Vue3的轻量级图像查看器&#xff0c;它基于Flip动画技术&#xff0c;支持PC和h5移动网页预览照片&#xff0c;如果它是Vue3开发的产品。 npm开源地址:https://www.npmjs.com/package/images-viewer-vue3?activeTabreadme Flip 动画 < …...

【深度学习】深入解析长短期记忆网络(LSTMs)

长短期记忆网络&#xff08;Long Short-Term Memory networks, LSTMs&#xff09;是一种特殊的递归神经网络&#xff08;RNN&#xff09;&#xff0c;专门设计用来解决标准 RNN 在处理长序列数据时的梯度消失和梯度爆炸问题。LSTMs 在许多序列数据任务中表现出色&#xff0c;如…...

从Web3到智能合约:探索新一代数据交互模式

随着互联网技术的不断演进&#xff0c;Web3的到来标志着互联网的一个新纪元。与传统的Web2相比&#xff0c;Web3倡导去中心化、更加开放和透明的网络架构&#xff0c;而智能合约则是其中的核心技术之一。本文将介绍Web3与智能合约的概念、应用以及它们如何改变数据交互模式&…...

排查bug的通用思路

⭐️前言⭐️ APP点击某个按钮没有反应/PC端执行某个操作后&#xff0c;响应较慢&#xff0c;通用的问题排查方法: 从多个角度来排查问题 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f349;博主将持续更新学习记录收获&#xff0c;友友们有任何问题可以在评…...

如何利用Python爬虫获得商品类目

在当今数字化时代&#xff0c;获取和分析数据的能力对于任何希望在市场上保持竞争力的企业来说都是至关重要的。对于电子商务平台和市场研究公司而言&#xff0c;获取商品类目数据尤为重要&#xff0c;因为这些数据可以帮助他们更好地理解市场趋势、优化产品目录并制定有效的营…...

如何通过 Windows 自带的启动管理功能优化电脑启动程序

在日常使用电脑的过程中&#xff0c;您可能注意到开机后某些程序会自动运行。这些程序被称为“自启动”或“启动项”&#xff0c;它们可以在系统启动时自动加载并开始运行&#xff0c;有时甚至在后台默默工作。虽然一些启动项可能是必要的&#xff08;如杀毒软件&#xff09;&a…...

大模型学习有什么发展前景?

前景人工智能大模型是指拥有超大规模参数&#xff08;通常在十亿个以上&#xff09;、复杂计算结构的机器学习模型。它通常能够处理海量数据&#xff0c;完成各种复杂任务&#xff0c;如自然语言处理、图像识别等。 2024年政府工作报告提出“发展新质生产力”&#xff0c;并将…...

Excel技巧:如何批量调整excel表格中的图片?

插入到excel表格中的图片大小不一&#xff0c;如何做到每张图片都完美的与单元格大小相同&#xff1f;并且能够根据单元格来改变大小&#xff1f;今天分享&#xff0c;excel表格里的图片如何批量调整大小。 方法如下&#xff1a; 点击表格中的一个图片&#xff0c;然后按住Ct…...

独著与编著的区别是?

独著和编著主要有以下区别&#xff1a; 一、创作性质 - 独著 - 独著是作者完全独立进行创作的作品。其内容是作者自己的研究成果、观点见解或者经验总结。作者从最初的选题构思&#xff0c;到资料收集、分析研究&#xff0c;再到内容撰写、修改润色等全过程都是独立完成的。…...

vue中pdf.js的使用,包括pdf显示,跳转指定页面,高亮关键词

目录 一、下载pdf.js 二、引入到本地的项目中 三、实现预览pdf 四、跳转到指定页面 五、利用pdf里面的find查找关键词 六、修改页面大小为实际大小 一、下载pdf.js https://github.com/mozilla/pdf.js 里面有很多的版本&#xff0c; 高版本的可能浏览器不兼容或者还要考…...

【Spring Boot】自动装配机制详解

1. 传统的 Spring 注入方式&#xff08;基于 XML 配置&#xff09; 在传统的 Spring 中&#xff0c;依赖注入&#xff08;DI&#xff09;通常通过 XML 配置文件来进行管理。常见的方式有两种&#xff1a; 通过 <property> 元素进行属性注入&#xff1a; <bean id&qu…...

Flink集群搭建整合Yarn运行

Flink 集群 1. 服务器规划 服务器h1、h4、h5 2. StandAlone 模式&#xff08;不推荐&#xff09; 2.1 会话模式 在h1操作 #1、解压 tar -zxvf flink-1.19.1-bin-scala_2.12.tgz -C /app/#2、修改配置文件 cd /app/flink-1.19.1/conf vim conf.yaml ##内容&#xff1a;## j…...

Linux Ubuntu 安装配置RabbitMQ,springboot使用RabbitMQ

rabbit-Ubuntu 一篇文章学会RabbitMQ 在Ubuntu上查看RabbitMQ状态可以通过多种方式进行&#xff0c;包括使用命令行工具和Web管理界面。以下是一些常用的方法&#xff1a; 1-使用systemctl命令&#xff1a; sudo systemctl start rabbitmq-server sudo systemctl status ra…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

React Native 导航系统实战(React Navigation)

导航系统实战&#xff08;React Navigation&#xff09; React Navigation 是 React Native 应用中最常用的导航库之一&#xff0c;它提供了多种导航模式&#xff0c;如堆栈导航&#xff08;Stack Navigator&#xff09;、标签导航&#xff08;Tab Navigator&#xff09;和抽屉…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

376. Wiggle Subsequence

376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...