当前位置: 首页 > 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. 对话框关闭时清理资源,避免性能问题。

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

http://www.lryc.cn/news/498507.html

相关文章:

  • 【银河麒麟操作系统真实案例分享】内存黑洞导致服务器卡死分析全过程
  • 如何加强游戏安全,防止定制外挂影响游戏公平性
  • SpringBoot整合knife4j,以及会遇到的一些bug
  • 城电科技|光伏廊道是什么?安装光伏廊道有什么好处?
  • 当DHCP服务器分配了同一个IP地址
  • 储能能量自动化调配装置功能介绍
  • vite5+vue3+Ts5 开源图片预览器上线
  • 【深度学习】深入解析长短期记忆网络(LSTMs)
  • 从Web3到智能合约:探索新一代数据交互模式
  • 排查bug的通用思路
  • 如何利用Python爬虫获得商品类目
  • 如何通过 Windows 自带的启动管理功能优化电脑启动程序
  • 大模型学习有什么发展前景?
  • Excel技巧:如何批量调整excel表格中的图片?
  • 独著与编著的区别是?
  • vue中pdf.js的使用,包括pdf显示,跳转指定页面,高亮关键词
  • 【Spring Boot】自动装配机制详解
  • Flink集群搭建整合Yarn运行
  • Linux Ubuntu 安装配置RabbitMQ,springboot使用RabbitMQ
  • 云数据库 MongoDB
  • Ionic 8.4 简介
  • 蓝桥杯系列---class1
  • vue3+elementPlus封装的一体表格
  • Junit5 单元测试入门
  • 数字信号处理-数学基础
  • 【Exp】# Microsoft Visual C++ Redistributable 各版本下载地址
  • Hive 分桶表的创建与填充操作详解
  • [小白系列]Ubuntu安装教程-安装prometheus和Grafana
  • Flask使用长连接
  • 数据分析思维案例:游戏评分低,怎么办?