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

彩带飘落效果

文章目录

  • 彩带效果
  • 适应场景
  • HTML版本
  • Vue3版本

彩带效果

彩带特效组件

适应场景

完成小结、版本升级等场景。提供HTM、Vue3版本。

HTML版本

<!doctype html>
<html lang="zh-CN"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>彩带效果</title><style>body {margin: 0;overflow: hidden;background-color: #f0f0f0;font-family: 'Arial', sans-serif;display: flex;justify-content: center;align-items: center;height: 100vh;}#confetti-container {position: fixed;top: 0;left: 0;width: 100%;height: 100%;pointer-events: none;z-index: 10;}.message-container {background: rgba(255, 255, 255, 0.8);padding: 20px;border-radius: 8px;text-align: center;z-index: 20;}.message {font-size: 2rem;font-weight: bold;margin-bottom: 20px;}button {padding: 12px 24px;background-color: #4caf50;color: white;border: none;border-radius: 4px;font-size: 18px;cursor: pointer;}button:hover {background-color: #45a049;}.confetti {position: absolute;width: 10px;height: 20px;}</style></head><body><div id="confetti-container"></div><div class="message-container"><div class="message">🎉 新功能上线啦!</div><button id="confetti-button">再来一次</button></div><script>// 容器document.getElementById('confetti-button').onclick = createConfetti// 页面加载后自动触发一次彩带效果window.onload = function () {setTimeout(createConfetti, 500)}function createConfetti() {// 清除现有彩带const container = document.getElementById('confetti-container')container.innerHTML = ''// 彩带颜色const colors = ['#f44336','#e91e63','#9c27b0','#673ab7','#3f51b5','#2196f3','#03a9f4','#00bcd4','#009688','#4CAF50','#8BC34A','#CDDC39','#FFEB3B','#FFC107','#FF9800','#FF5722',]// 物理参数 - 烟花效果const gravity = 0.25 // 重力加速度 - 增强const initialVelocity = 20 // 基础初始速度 - 显著提高const velocityVariation = 8 // 速度变化幅度const dragCoefficient = 0.98 // 阻力系数 - 稍微增加以模拟空气阻力// 创建彩带 - 增加数量以创造更密集的效果for (let i = 0; i < 200; i++) {setTimeout(function () {const confetti = document.createElement('div')confetti.className = 'confetti'// 随机彩带特性const color = colors[Math.floor(Math.random() * colors.length)]const shape =Math.random() < 0.33 ? 'circle' : Math.random() < 0.66 ? 'rectangle' : 'triangle'const size = Math.random() * 10 + 5// 从两侧喷出 - 随机选择左侧或右侧const side = Math.random() < 0.5 ? 'left' : 'right'const xPos = side === 'left' ? 0 : window.innerWidthconst yPos = window.innerHeight * 0.8 + Math.random() * window.innerHeight * 0.2 // 更靠近底部发射// 角度设置 - 更多向上的角度,像烟花发射let angleif (side === 'left') {angle = -Math.PI / 2 + (Math.random() * Math.PI) / 4 // -90度到-45度(强烈向上偏右)} else {angle = (Math.PI * 3) / 2 - (Math.random() * Math.PI) / 4 // 225度到270度(强烈向上偏左)}// 初始速度 - 更高的初速度模拟烟花发射const velocity = initialVelocity + Math.random() * velocityVariation// 设置初始位置和样式confetti.style.left = xPos + 'px'confetti.style.top = yPos + 'px'confetti.style.width = size + 'px'confetti.style.height = size + 'px'confetti.style.backgroundColor = colorconfetti.style.transform = 'rotate(' + Math.random() * 360 + 'deg)'// 设置不同形状if (shape === 'circle') {confetti.style.borderRadius = '50%'} else if (shape === 'triangle') {confetti.style.width = '0'confetti.style.height = '0'confetti.style.backgroundColor = 'transparent'confetti.style.borderLeft = size / 2 + 'px solid transparent'confetti.style.borderRight = size / 2 + 'px solid transparent'confetti.style.borderBottom = size + 'px solid ' + color}container.appendChild(confetti)// 动画参数let xVelocity = Math.cos(angle) * velocitylet yVelocity = Math.sin(angle) * velocityconst rotateVel = Math.random() * 0.2 - 0.1let rotation = Math.random() * 360// 时间跟踪(毫秒)let time = 0const initialBurstDuration = 500 // 初始高速喷射持续500毫秒let lastTimestamp = performance.now()// 动画函数function animate(timestamp) {// 计算时间差const deltaTime = timestamp - lastTimestamplastTimestamp = timestamptime += deltaTime// 应用物理效果if (time < initialBurstDuration) {// 初始爆发阶段 - 保持高速,稍微减速yVelocity *= 0.99xVelocity *= 0.99} else {// 自由落体阶段yVelocity += gravityxVelocity *= dragCoefficient}// 更新位置const currentX = parseFloat(confetti.style.left)const currentY = parseFloat(confetti.style.top)confetti.style.left = currentX + xVelocity + 'px'confetti.style.top = currentY + yVelocity + 'px'// 旋转彩带rotation += rotateVelconfetti.style.transform = 'rotate(' + rotation + 'deg)'// 超出屏幕移除彩带if (currentY < window.innerHeight + 100 &&currentX > -100 &&currentX < window.innerWidth + 100) {requestAnimationFrame(animate)} else {confetti.remove()}}// 启动动画requestAnimationFrame(animate)}, Math.random() * 800) // 缩短发射间隔,使效果更集中}}</script></body>
</html>

Vue3版本

<template><div class="confetti-container" ref="confettiContainer"></div><div class="message-container"><div class="message">🎉 新功能上线啦!</div><button @click="createConfetti">再来一次</button></div>
</template><script setup>
import { ref, onMounted } from 'vue'// confetti容器的引用
const confettiContainer = ref(null)// 组件挂载时触发confetti效果
onMounted(() => {setTimeout(createConfetti, 500)
})function createConfetti() {// 清除现有的confettiif (confettiContainer.value) {confettiContainer.value.innerHTML = ''}// confetti的颜色数组const colors = ['#f44336','#e91e63','#9c27b0','#673ab7','#3f51b5','#2196f3','#03a9f4','#00bcd4','#009688','#4CAF50','#8BC34A','#CDDC39','#FFEB3B','#FFC107','#FF9800','#FF5722',]// 物理参数const gravity = 0.25 // 重力const initialVelocity = 20 // 初始速度const velocityVariation = 8 // 速度变化范围const dragCoefficient = 0.98 // 阻力系数// 创建confettifor (let i = 0; i < 200; i++) {setTimeout(() => {const confetti = document.createElement('div')confetti.className = 'confetti'// 随机confetti属性const color = colors[Math.floor(Math.random() * colors.length)]const shape =Math.random() < 0.33 ? 'circle' : Math.random() < 0.66 ? 'rectangle' : 'triangle'const size = Math.random() * 10 + 5// 从两侧发射const side = Math.random() < 0.5 ? 'left' : 'right'const xPos = side === 'left' ? 0 : window.innerWidth - sizeconst yPos = window.innerHeight * 0.8 + Math.random() * window.innerHeight * 0.2// 烟花般发射的角度let angleif (side === 'left') {angle = -Math.PI / 2 + (Math.random() * Math.PI) / 4 // -90° 到 -45°} else {angle = (Math.PI * 3) / 2 - (Math.random() * Math.PI) / 4 // 225° 到 270°}// 初始速度const velocity = initialVelocity + Math.random() * velocityVariation// 设置初始位置和样式confetti.style.position = 'absolute'confetti.style.left = xPos + 'px'confetti.style.top = yPos + 'px'confetti.style.width = size + 'px'confetti.style.height = size + 'px'confetti.style.backgroundColor = colorconfetti.style.transform = `rotate(${Math.random() * 360}deg)`// 设置形状样式if (shape === 'circle') {confetti.style.borderRadius = '50%'} else if (shape === 'triangle') {confetti.style.width = '0'confetti.style.height = '0'confetti.style.backgroundColor = 'transparent'confetti.style.borderLeft = `${size / 2}px solid transparent`confetti.style.borderRight = `${size / 2}px solid transparent`confetti.style.borderBottom = `${size}px solid ${color}`}confettiContainer.value.appendChild(confetti)// 动画参数let xVelocity = Math.cos(angle) * velocitylet yVelocity = Math.sin(angle) * velocityconst rotateVel = Math.random() * 0.2 - 0.1let rotation = Math.random() * 360// 时间追踪let time = 0const initialBurstDuration = 500let lastTimestamp = performance.now()// 动画函数function animate(timestamp) {const deltaTime = (timestamp - lastTimestamp) / 1000 // 转换为秒lastTimestamp = timestamptime += deltaTime * 1000 // 以毫秒为单位追踪时间// 应用物理效果if (time < initialBurstDuration) {// 初始爆发阶段yVelocity *= Math.pow(0.99, deltaTime * 120) // 帧率调整后的阻力xVelocity *= Math.pow(0.99, deltaTime * 120)} else {// 自由落体阶段yVelocity += gravity * deltaTime * 60 // 应用重力xVelocity *= Math.pow(dragCoefficient, deltaTime * 60) // 应用阻力}// 更新位置const currentX = parseFloat(confetti.style.left || '0')const currentY = parseFloat(confetti.style.top || '0')confetti.style.left = currentX + xVelocity * deltaTime * 60 + 'px'confetti.style.top = currentY + yVelocity * deltaTime * 60 + 'px'// 旋转confettirotation += rotateVel * deltaTime * 60confetti.style.transform = `rotate(${rotation}deg)`// 仅当confetti落到屏幕下方或超出两侧时移除if (currentY < window.innerHeight + 100 &&currentX > -100 &&currentX < window.innerWidth + 100) {requestAnimationFrame(animate)} else if (currentY >= window.innerHeight + 100) {confetti.remove() // 仅当落到下方时移除} else {requestAnimationFrame(animate) // 如果在上方或两侧则继续}}requestAnimationFrame(animate)}, Math.random() * 800)}
}
</script><style scoped>
:deep(html),
:deep(body) {margin: 0;overflow: hidden;background-color: #f0f0f0;font-family: 'Arial', sans-serif;display: flex;justify-content: center;align-items: center;height: 100vh;width: 100vw;
}.confetti-container {position: fixed;top: 0;left: 0;width: 100vw;height: 100vh;pointer-events: none;z-index: 10;
}.message-container {/* background: rgba(255, 255, 255, 0.8); */padding: 20px;border-radius: 8px;text-align: center;z-index: 20;padding-top: 17%;
}.message {font-size: 2rem;font-weight: bold;margin-bottom: 20px;color: #fff;
}button {padding: 12px 24px;background-color: #4caf50;color: white;border: none;border-radius: 4px;font-size: 18px;cursor: pointer;
}button:hover {background-color: #45a049;
}.confetti {position: absolute;width: 10px;height: 20px;
}
</style>
http://www.xdnf.cn/news/243523.html

相关文章:

  • 大学之大:香港理工大学2025.5.1
  • 返回类型后置 和 auto推导返回值类型
  • Vue 3 中通过 this. 调用 setup 暴露的函数
  • 使用CubeMX新建DMA工程——存储器到外设模式
  • 21 课时精通生成式 AI:微软官方入门指南详解
  • 人工智能发展对未来IT从业岗位的展望
  • Java大厂硬核面试:Flink流处理容错、Pomelo JVM调优、MyBatis二级缓存穿透防护与Kubernetes服务网格实战解析
  • Rust多线程性能优化:打破Arc+锁的瓶颈,效率提升10倍
  • SpringBoot研究生双选系统开发实现
  • 图与网络模型
  • C#实现主流PLC读写工具类封装
  • 设计模式简述(十五)观察者模式
  • OpenGL-ES 学习(15) ----纹理
  • x86_64 Linux使用avx指令(补充)
  • RISC-V AIA SPEC学习(四)
  • python如何把pdf转word
  • (33)VTK C++开发示例 ---图片转3D
  • Lucene多种数据类型使用说明
  • 文献阅读篇#5:5月一区好文阅读,BFA-YOLO,用于建筑信息建模!(上)
  • 段永平浙大访谈精华:长期主义的知行合一
  • 类成员函数编译链接的过程
  • Spark-小练试刀
  • centos7 离线安装python3 保留python2
  • 华为eNSP:多区域集成IS-IS
  • 数据升降级:医疗数据的“时空穿梭“系统工程(分析与架构篇)
  • Linux btop 使用教程
  • 三元运算符与扩展运算符
  • Java 中的 CopyOnWriteArrayList
  • 11.多边形的三角剖分 (Triangulation) : 画廊问题
  • Postgresql源码(145)优化器nestloop参数化路径评估不准问题分析