今天想着登录页太俗了,用AI给登录页面整一个动态粒子效果。没想到效果还很不错,以下是实现的功能描述:
✨ 粒子效果特性
1. 粒子系统
- 根据屏幕大小自动生成粒子数量
- 每个粒子有随机位置、速度、大小和透明度
- 使用蓝色系(#1890ff)粒子
2. 鼠标交互
- 粒子会被鼠标吸引
- 在鼠标 150px 范围内的粒子会受到引力影响
- 越靠近鼠标,吸引力越强
3. 物理效果
- 粒子有摩擦力,速度会逐渐衰减
- 粒子会在边界反弹
- 平滑的运动效果
4. 视觉连线
- 距离较近的粒子之间会绘制连线
- 线条透明度根据距离动态变化
- 距离越近,线条越明显
5. 性能优化
- 使用 Canvas 2D 渲染,性能良好
- 自适应屏幕大小
- 组件卸载时自动清理资源
🎨 视觉效果
- 粒子颜色: 蓝色系(主题色 #1890ff)
- 粒子连线: 半透明蓝色连线
- 背景: 保持原有的深色渐变背景
- 动画: 持续循环动画,60fps
然后把这些描述喂给AI,您可以得到一个粒子跟随鼠标移动的动态效果!
以下就是我得到的代码,
<canvas ref="particleCanvas" class="particle-canvas"></canvas>
<script setup lang="ts">
import { reactive, ref, onMounted, onBeforeUnmount } from 'vue'
// 粒子系统
const particleCanvas = ref<HTMLCanvasElement>()
let animationId: number
let particles: Particle[] = []
let mouse = { x: 0, y: 0 }
class Particle {
x: number
y: number
vx: number
vy: number
radius: number
color: string
alpha: number
constructor(canvas: HTMLCanvasElement) {
this.x = Math.random() * canvas.width
this.y = Math.random() * canvas.height
this.vx = (Math.random() - 0.5) * 0.5
this.vy = (Math.random() - 0.5) * 0.5
this.radius = Math.random() * 2 + 1
this.color = `rgba(24, 144, 255, ${Math.random() * 0.5 + 0.2})`
this.alpha = Math.random() * 0.5 + 0.5
}
update(canvas: HTMLCanvasElement, mouseX: number, mouseY: number) {
// 鼠标影响
const dx = mouseX - this.x
const dy = mouseY - this.y
const distance = Math.sqrt(dx * dx + dy * dy)
const maxDistance = 150
if (distance < maxDistance) {
const force = (maxDistance - distance) / maxDistance
const angle = Math.atan2(dy, dx)
this.vx += Math.cos(angle) * force * 0.5
this.vy += Math.sin(angle) * force * 0.5
}
// 摩擦力
this.vx *= 0.99
this.vy *= 0.99
// 更新位置
this.x += this.vx
this.y += this.vy
// 边界检测
if (this.x < 0 || this.x > canvas.width) this.vx *= -1
if (this.y < 0 || this.y > canvas.height) this.vy *= -1
}
draw(ctx: CanvasRenderingContext2D) {
ctx.beginPath()
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2)
ctx.fillStyle = this.color
ctx.fill()
}
}
function initParticles() {
if (!particleCanvas.value) return
const canvas = particleCanvas.value
const ctx = canvas.getContext('2d')
if (!ctx) return
// 设置画布尺寸
canvas.width = window.innerWidth
canvas.height = window.innerHeight
// 创建粒子
const particleCount = Math.floor((canvas.width * canvas.height) / 10000)
particles = []
for (let i = 0; i < particleCount; i++) {
particles.push(new Particle(canvas))
}
// 鼠标移动事件
const handleMouseMove = (e: MouseEvent) => {
mouse.x = e.clientX
mouse.y = e.clientY
}
// 窗口大小改变事件
const handleResize = () => {
canvas.width = window.innerWidth
canvas.height = window.innerHeight
}
window.addEventListener('mousemove', handleMouseMove)
window.addEventListener('resize', handleResize)
// 动画循环
function animate() {
if (!ctx || !canvas) return
ctx.clearRect(0, 0, canvas.width, canvas.height)
// 更新和绘制粒子
particles.forEach(particle => {
particle.update(canvas, mouse.x, mouse.y)
particle.draw(ctx)
})
// 绘制连线
particles.forEach((p1, i) => {
particles.slice(i + 1).forEach(p2 => {
const dx = p1.x - p2.x
const dy = p1.y - p2.y
const distance = Math.sqrt(dx * dx + dy * dy)
if (distance < 100) {
ctx.beginPath()
ctx.moveTo(p1.x, p1.y)
ctx.lineTo(p2.x, p2.y)
ctx.strokeStyle = `rgba(24, 144, 255, ${0.2 * (1 - distance / 100)})`
ctx.lineWidth = 0.5
ctx.stroke()
}
})
})
animationId = requestAnimationFrame(animate)
}
animate()
// 清理函数
return () => {
window.removeEventListener('mousemove', handleMouseMove)
window.removeEventListener('resize', handleResize)
cancelAnimationFrame(animationId)
}
}
onMounted(() => {
initParticles()
})
onBeforeUnmount(() => {
if (animationId) {
cancelAnimationFrame(animationId)
}
})
我是用的智谱 GLM-5.0 模型,整体效果还是很不错的!!!