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

vue3 随机生产音符扩散效果

  1 <template>
  2   <div class="container">
  3     <div class="flower-center"></div>
  4     <div 
  5       class="note-petal"
  6       v-for="note in activeNotes"
  7       :key="note.id"
  8       :style="note.style"
  9     >
 10       {{ note.symbol }}
 11     </div>
 12     <div class="controls">
 13       <button @click="toggleAnimation">{{ isPlaying ? '暂停动画' : '播放动画' }}</button>
 14     </div>
 15   </div>
 16 </template>
 17 
 18 <script setup>
 19 import { ref, onMounted, onUnmounted } from 'vue'
 20 
 21 const activeNotes = ref([])
 22 const isPlaying = ref(true)
 23 let animationInterval = null
 24 let noteCounter = 0
 25 
 26 const noteSymbols = ['', '', '', '', '', '', '']
 27 const colors = [
 28   '#ff6b6b', '#4ecdc4', '#ffbe76', 
 29   '#a5d8ff', '#d8b4fe', '#ff9e9e', '#b5ead7'
 30 ]
 31 
 32 function createPetalGroup() {
 33   const newNotes = []
 34   // 随机生成5-12个音符
 35   const noteCount = Math.floor(Math.random() * 8) + 5
 36   
 37   for (let i = 0; i < noteCount; i++) {
 38     const angle = (i * (Math.PI * 2 / noteCount)) + (Math.random() * 0.5 - 0.25)
 39     const distance = 300 + Math.random() * 150
 40     const endX = Math.cos(angle) * distance
 41     const endY = Math.sin(angle) * distance
 42     const rotation = (Math.random() * 60 - 30)
 43     
 44     const noteId = `note-${Date.now()}-${noteCounter++}`
 45     
 46     newNotes.push({
 47       id: noteId,
 48       symbol: noteSymbols[Math.floor(Math.random() * noteSymbols.length)],
 49       style: {
 50         color: colors[Math.floor(Math.random() * colors.length)],
 51         '--end-x': `${endX}px`,
 52         '--end-y': `${endY}px`,
 53         '--rotation': `${rotation}deg`,
 54         'animation-duration': `${3 + Math.random() * 1.5}s`
 55       }
 56     })
 57   }
 58   
 59   activeNotes.value = [...activeNotes.value, ...newNotes]
 60   
 61   setTimeout(() => {
 62     activeNotes.value = activeNotes.value.filter(note => !newNotes.some(newNote => newNote.id === note.id))
 63   }, 4000)
 64 }
 65 
 66 function startAnimation() {
 67   if (animationInterval) clearInterval(animationInterval)
 68   createPetalGroup()
 69   animationInterval = setInterval(createPetalGroup, 1200)
 70   isPlaying.value = true
 71 }
 72 
 73 function stopAnimation() {
 74   clearInterval(animationInterval)
 75   isPlaying.value = false
 76 }
 77 
 78 function toggleAnimation() {
 79   if (isPlaying.value) {
 80     stopAnimation()
 81   } else {
 82     startAnimation()
 83   }
 84 }
 85 
 86 onMounted(() => {
 87   startAnimation()
 88 })
 89 
 90 onUnmounted(() => {
 91   stopAnimation()
 92 })
 93 </script>
 94 
 95 <style>
 96 .container {
 97   position: relative;
 98   width: 100vw;
 99   height: 100vh;
100   background: radial-gradient(circle at center, #1a2a6c, #2a5298);
101   overflow: hidden;
102 }
103 
104 .flower-center {
105   position: absolute;
106   width: 120px;
107   height: 120px;
108   top: 50%;
109   left: 50%;
110   transform: translate(-50%, -50%);
111   background: radial-gradient(circle, rgba(255,255,255,0.9) 0%, rgba(255,255,255,0) 80%);
112   border-radius: 50%;
113   z-index: 1;
114   animation: flowerPulse 3s ease-in-out infinite;
115 }
116 
117 @keyframes flowerPulse {
118   0%, 100% { transform: translate(-50%, -50%) scale(1); opacity: 0.8; }
119   50% { transform: translate(-50%, -50%) scale(1.4); opacity: 1; }
120 }
121 
122 .note-petal {
123   position: absolute;
124   font-size: 48px;
125   top: 50%;
126   left: 50%;
127   transform: translate(-50%, -50%);
128   animation: petalBloom 4s ease-out forwards;
129   opacity: 0;
130   text-shadow: 0 0 20px currentColor;
131   z-index: 10;
132   will-change: transform, opacity;
133 }
134 
135 @keyframes petalBloom {
136   0% {
137     transform: translate(-50%, -50%) scale(0.5) rotate(0deg);
138     opacity: 0;
139     filter: blur(3px);
140   }
141   20% {
142     opacity: 1;
143     transform: translate(-50%, -50%) scale(1) rotate(0deg);
144     filter: blur(0);
145   }
146   80% {
147     opacity: 0.7;
148   }
149   100% {
150     transform: translate(var(--end-x), var(--end-y)) scale(0.3) rotate(var(--rotation));
151     opacity: 0;
152     filter: blur(2px);
153   }
154 }
155 
156 .controls {
157   position: absolute;
158   bottom: 40px;
159   left: 50%;
160   transform: translateX(-50%);
161   z-index: 100;
162 }
163 
164 button {
165   padding: 12px 24px;
166   background: linear-gradient(45deg, #ff6b6b, #ff8e8e);
167   border: none;
168   border-radius: 30px;
169   color: white;
170   font-weight: bold;
171   cursor: pointer;
172   transition: all 0.3s;
173   box-shadow: 0 4px 15px rgba(255, 107, 107, 0.4);
174 }
175 
176 button:hover {
177   transform: translateY(-3px);
178   box-shadow: 0 6px 20px rgba(255, 107, 107, 0.6);
179 }
180 </style>

 

http://www.jsqmd.com/news/47318/

相关文章:

  • ASM1042A3S车规级CANFD芯片在两轮车和平衡车控制器优秀的方案中的技术应用
  • 2025抚州一对一辅导测评排行榜:高性价比平台推荐,提分效果实测
  • Linux中: 一个服务器上运行多个Redis服务,应该保证哪些配置不一致
  • 青岛市一对一教育机构推荐,2026课外家教补习机构权威排行榜
  • AI元人文:首论客观值的表征
  • 2025吉安市一对一辅导测评排行榜:高性价比平台权威推荐
  • 2025年别墅供暖厂家权威推荐榜单:别墅锅炉/联排别墅供暖/小别墅供暖源头厂家精选
  • 面向对象第一次大作业 - nanqiu
  • 2025年11月央国企求职机构选择指南:权威榜单与避坑要点
  • 济南市一对一培训机构排行榜:权威榜单发布2026年综合评分前十强机构推荐
  • 2025年高浮雕优质厂家权威推荐榜单:石浮雕/大理石浮雕/中式石浮雕源头厂家精选
  • 2025 年 11 月预制袋套袋机,袋中袋套袋机,食品套袋机,八边封套袋机最新推荐,产能、专利、环保三维数据透视!
  • 2025 年 11 月侧推式套袋机,卧式套袋机,M型袋套袋机最新推荐,产能、专利、环保三维数据透视!
  • AT AGC005 题解
  • Spring Security-PasswordEncoder密码解析器详解和自定义登录逻辑
  • 2025 胶管厂家最新推荐排行榜:耐高压 35MPa / 热熔 / 特种工况优质品牌精选矿用/大口径吸排泥/低压/耐高温/钢丝编制/输油胶管公司推荐
  • 2025 装盒机厂家最新推荐排行榜:全自动 / 食品 / 纸巾 / 卫生巾装盒机权威测评,技术创新与整线配套能力
  • 模板进阶:从非类型参数到分离编译,吃透 C++ 泛型编程的核心逻辑 - 详解
  • 机械 / 汽车 / 电子设计师必看!Creo 11.0 下载安装,创成式设计 + 实时仿真
  • Linux 中截取文本的最后几个字符
  • 2025年新疆初三复读班权威推荐榜单:中考复读/初三集训班/本地中考复读学校精选
  • 11.20题解
  • 11.21题解
  • 黔东南苗族侗族自治州一对一家教机构推荐,2025教育机构靠谱测评排行榜
  • 面向对象程序设计-三次单部电梯调度问题总结
  • 2025年鹌鹑蛋蒸煮剥壳流水线实力厂家权威推荐榜单:鹌鹑蛋煮蛋机/鹌鹑蛋剥壳机/鹌鹑蛋剥壳线源头厂家精选
  • NHVR-20 型油气回收在线监测系统:工业级全场景油气泄漏防控方案 - 详解
  • 9 个步骤教你如何安全地迁移数据库或字段
  • 衡水市一对一家教机构推荐,2026最新辅导机构口碑排行榜
  • 黔西南布依族苗族自治州一对一家教机构推荐,2025最新教育机构权威测评榜单