| 1. Canvas 初始化 | 设置 Canvas 尺寸适配窗口、获取 2D 上下文 |
| 2. 粒子类封装 | 定义粒子属性(位置、速度、颜色、大小)和方法(更新、绘制) |
| 3. 动画循环 | 逐帧清空画布 → 更新粒子状态 → 绘制粒子 |
| 4. 交互逻辑 | 监听鼠标 / 触摸事件,修改粒子运动规则 |
| 5. 边界 / 碰撞处理 | 粒子超出画布反弹、粒子间距离判断 |
| 6. 扩展效果 | 粒子连线、颜色渐变、生命周期(出生 / 消亡) |

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>七彩粒子</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #0f2027;
min-height: 100vh;
overflow: hidden;
font-family: 'Arial', sans-serif;
}
canvas {
position: fixed;
top: 0;
left: 0;
width: 100%%;
height: 100%%;
z-index: 1;
}
.footer {
position: fixed;
bottom: 0;
width: 100%%;
padding: 12px;
text-align: center;
color: rgba(255,255,255,0.7);
background: rgba(0,0,0,0.3);
backdrop-filter: blur(3px);
font-size: 0.9rem;
z-index: 10;
}
</style>
</head>
<body>
<canvas id="particleCanvas"></canvas>
<div class="footer">七彩粒子网络效果 | Canvas 实现 | 支持鼠标交互</div>
<script>
// ========== 配置项(可自定义) ==========
const CONFIG = {
particleCount: 300, // 粒子数量
particleSize: 1.5, // 粒子大小
speedFactor: 1, // 运动速度
lineMaxDistance: 6000, // 粒子连线最大距离(平方值)
mouseMaxDistance: 20000,// 鼠标交互最大距离(平方值)
hueStep: 0.1, // 颜色渐变步长
lineOpacity: 0.6, // 连线透明度
lineWidthRatio: 1.5 // 连线宽度比例
};
// ========== Canvas 基础配置 ==========
const canvas = document.getElementById('particleCanvas');
const ctx = canvas.getContext('2d');
let mouse = { x: null, y: null }; // 鼠标位置
// 适配窗口大小
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// 监听鼠标事件
window.addEventListener('mousemove', (e) => {
mouse.x = e.clientX;
mouse.y = e.clientY;
});
window.addEventListener('mouseout', () => {
mouse.x = null;
mouse.y = null;
});
// ========== 粒子类 ==========
class Particle {
constructor() {
// 初始位置(随机)
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
// 初始速度(-1 ~ 1 随机)
this.vx = (Math.random() - 0.5) * 2;
this.vy = (Math.random() - 0.5) * 2;
// 初始色相(0 ~ 360)
this.hue = Math.floor(Math.random() * 360);
}
// 更新粒子状态(位置、颜色、边界反弹)
update() {
// 移动粒子
this.x += this.vx * CONFIG.speedFactor;
this.y += this.vy * CONFIG.speedFactor;
// 边界反弹
if (this.x < 0 || this.x > canvas.width) this.vx *= -1;
if (this.y < 0 || this.y > canvas.height) this.vy *= -1;
// 颜色渐变
this.hue = (this.hue + CONFIG.hueStep) %% 360;
}
// 绘制粒子(圆形)
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, CONFIG.particleSize, 0, Math.PI * 2);
ctx.fillStyle = `hsl(${this.hue}, 100%%, 65%%)`;
ctx.fill();
}
}
// ========== 粒子系统 ==========
let particles = [];
// 初始化粒子
function initParticles() {
particles = [];
for (let i = 0; i < CONFIG.particleCount; i++) {
particles.push(new Particle());
}
}
// 绘制粒子间连线
function drawLines(particle, target) {
if (!target.x || !target.y) return;
// 计算粒子与目标的距离(平方值,避免开方提升性能)
const dx = particle.x - target.x;
const dy = particle.y - target.y;
const distanceSq = dx * dx + dy * dy;
// 判断是否在连线范围内
const maxDist = target === mouse ? CONFIG.mouseMaxDistance : CONFIG.lineMaxDistance;
if (distanceSq > maxDist) return;
// 距离比例(0 ~ 1)
const ratio = (maxDist - distanceSq) / maxDist;
// 鼠标交互:粒子向鼠标反方向移动
if (target === mouse && distanceSq > maxDist / 2) {
particle.x -= dx * 0.03 * CONFIG.speedFactor;
particle.y -= dy * 0.03 * CONFIG.speedFactor;
}
// 绘制连线
ctx.beginPath();
ctx.lineWidth = ratio / CONFIG.lineWidthRatio;
const lineHue = (particle.hue + ratio * 60) %% 360;
ctx.strokeStyle = `hsla(${lineHue}, 90%%, 70%%, ${ratio * CONFIG.lineOpacity})`;
ctx.moveTo(particle.x, particle.y);
ctx.lineTo(target.x, target.y);
ctx.stroke();
}
// 动画主循环
function animate() {
// 清空画布(半透明叠加,可选:增加拖影效果)
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 若要拖影效果,替换为:ctx.fillStyle = 'rgba(15,32,39,0.1)'; ctx.fillRect(0,0,canvas.width,canvas.height);
// 遍历所有粒子,更新并绘制
particles.forEach(particle => {
particle.update();
particle.draw();
// 绘制粒子与鼠标的连线
drawLines(particle, mouse);
// 绘制粒子与其他粒子的连线
particles.forEach(otherParticle => {
if (particle !== otherParticle) {
drawLines(particle, otherParticle);
}
});
});
requestAnimationFrame(animate);
}
// 初始化并启动动画
initParticles();
animate();
</script>
</body>
</html>
本文最后更新时间 2025-12-16
文章链接地址:https://xzlo.blog/index.php/archives/94/
本站文章除注明[转载|引用|原文]出处外,均为本站原生内容,转载前请注明出处