前端实现粒子互动背景:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>粒子互动背景</title>
<!-- 引入Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>
<!-- 引入Font Awesome -->
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<!-- 配置Tailwind -->
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#3B82F6',
secondary: '#8B5CF6',
accent: '#10B981',
dark: '#1E293B',
},
fontFamily: {
inter: ['Inter', 'sans-serif'],
},
},
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
.glass {
@apply bg-white/10 backdrop-blur-md border border-white/20;
}
.btn-effect {
@apply transition-all duration-300 hover:scale-105 active:scale-95;
}
}
</style>
<style>
body {
margin: 0;
overflow: hidden;
font-family: 'Inter', sans-serif;
}
#canvas {
display: block;
position: absolute;
top: 0;
left: 0;
z-index: 0;
}
.control-panel {
transition: transform 0.3s ease, opacity 0.3s ease;
}
.panel-hidden {
transform: translateX(-100%);
opacity: 0;
pointer-events: none;
}
.toggle-btn {
transition: transform 0.3s ease;
}
.toggle-btn.rotated {
transform: rotate(180deg);
}
</style>
</head>
<body class="bg-dark text-white">
<!-- 粒子画布 -->
<canvas id="canvas"></canvas>
<!-- 主标题 -->
<div class="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 z-10 text-center">
<h1 class="text-[clamp(2rem,5vw,4rem)] font-bold mb-4 bg-clip-text text-transparent bg-gradient-to-r from-primary to-secondary">
粒子互动背景
</h1>
<p class="text-[clamp(1rem,2vw,1.25rem)] text-white/80 max-w-md mx-auto">
移动鼠标与粒子互动,点击左侧按钮打开控制面板调整效果
</p>
</div>
<!-- 控制面板 -->
<div id="controlPanel" class="control-panel fixed top-0 left-0 h-full glass p-6 w-80 z-20 overflow-y-auto">
<div class="flex justify-between items-center mb-8">
<h2 class="text-2xl font-bold">控制面板</h2>
<button id="togglePanel" class="toggle-btn text-2xl btn-effect">
<i class="fa fa-chevron-left"></i>
</button>
</div>
<div class="space-y-6">
<!-- 粒子数量控制 -->
<div>
<label class="block mb-2 text-white/80">粒子数量: <span id="particleCountValue">100</span></label>
<input type="range" id="particleCount" min="50" max="300" value="100"
class="w-full h-2 bg-white/20 rounded-lg appearance-none cursor-pointer accent-primary">
</div>
<!-- 粒子速度控制 -->
<div>
<label class="block mb-2 text-white/80">粒子速度: <span id="particleSpeedValue">1</span></label>
<input type="range" id="particleSpeed" min="0.5" max="5" step="0.5" value="1"
class="w-full h-2 bg-white/20 rounded-lg appearance-none cursor-pointer accent-primary">
</div>
<!-- 连线距离控制 -->
<div>
<label class="block mb-2 text-white/80">连线距离: <span id="connectionDistanceValue">150</span></label>
<input type="range" id="connectionDistance" min="50" max="300" value="150"
class="w-full h-2 bg-white/20 rounded-lg appearance-none cursor-pointer accent-primary">
</div>
<!-- 鼠标引力控制 -->
<div>
<label class="block mb-2 text-white/80">鼠标引力: <span id="mouseForceValue">50</span></label>
<input type="range" id="mouseForce" min="0" max="200" value="50"
class="w-full h-2 bg-white/20 rounded-lg appearance-none cursor-pointer accent-primary">
</div>
<!-- 粒子大小控制 -->
<div>
<label class="block mb-2 text-white/80">粒子大小: <span id="particleSizeValue">2</span></label>
<input type="range" id="particleSize" min="1" max="10" value="2"
class="w-full h-2 bg-white/20 rounded-lg appearance-none cursor-pointer accent-primary">
</div>
<!-- 主题颜色选择 -->
<div>
<label class="block mb-2 text-white/80">主题颜色</label>
<div class="flex gap-3">
<button class="theme-btn w-8 h-8 rounded-full bg-gradient-to-r from-primary to-secondary btn-effect" data-theme="blue"></button>
<button class="theme-btn w-8 h-8 rounded-full bg-gradient-to-r from-pink-500 to-rose-500 btn-effect" data-theme="pink"></button>
<button class="theme-btn w-8 h-8 rounded-full bg-gradient-to-r from-accent to-emerald-400 btn-effect" data-theme="green"></button>
<button class="theme-btn w-8 h-8 rounded-full bg-gradient-to-r from-amber-500 to-orange-500 btn-effect" data-theme="orange"></button>
<button class="theme-btn w-8 h-8 rounded-full bg-gradient-to-r from-zinc-400 to-zinc-800 btn-effect" data-theme="gray"></button>
</div>
</div>
<!-- 重置按钮 -->
<button id="resetBtn" class="w-full py-3 rounded-lg bg-white/10 hover:bg-white/20 transition-all duration-300 btn-effect">
<i class="fa fa-refresh mr-2"></i>重置所有设置
</button>
</div>
</div>
<script>
// 获取画布和上下文
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// 设置画布尺寸
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
// 初始化尺寸并监听窗口大小变化
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// 粒子类
class Particle {
constructor() {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.size = particleSize;
this.speedX = (Math.random() - 0.5) * particleSpeed;
this.speedY = (Math.random() - 0.5) * particleSpeed;
this.color = primaryColor;
}
// 更新粒子位置
update() {
this.x += this.speedX;
this.y += this.speedY;
// 边界检测
if (this.x < 0 || this.x > canvas.width) this.speedX *= -1;
if (this.y < 0 || this.y > canvas.height) this.speedY *= -1;
// 鼠标引力效果
if (mouse.x && mouse.y) {
const dx = mouse.x - this.x;
const dy = mouse.y - this.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < mouseForce) {
const force = (mouseForce - distance) / mouseForce;
this.x += dx * force * 0.1;
this.y += dy * force * 0.1;
}
}
}
// 绘制粒子
draw() {
ctx.fillStyle = this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fill();
}
}
// 粒子数组
let particles = [];
// 配置参数
let particleCount = 100;
let particleSpeed = 1;
let connectionDistance = 150;
let mouseForce = 50;
let particleSize = 2;
let primaryColor = '#3B82F6';
let secondaryColor = '#8B5CF6';
// 鼠标位置
const mouse = {
x: null,
y: null,
radius: 150
};
// 初始化粒子
function init() {
particles = [];
for (let i = 0; i < particleCount; i++) {
particles.push(new Particle());
}
}
// 连接粒子
function connectParticles() {
for (let a = 0; a < particles.length; a++) {
for (let b = a; b < particles.length; b++) {
const dx = particles[a].x - particles[b].x;
const dy = particles[a].y - particles[b].y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < connectionDistance) {
const opacity = 1 - (distance / connectionDistance);
ctx.strokeStyle = `rgba(139, 92, 246, ${opacity})`;
ctx.lineWidth = 0.5;
ctx.beginPath();
ctx.moveTo(particles[a].x, particles[a].y);
ctx.lineTo(particles[b].x, particles[b].y);
ctx.stroke();
}
}
}
}
// 动画循环
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 绘制渐变背景
const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
gradient.addColorStop(0, '#0F172A');
gradient.addColorStop(1, '#1E293B');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 更新和绘制所有粒子
for (let i = 0; i < particles.length; i++) {
particles[i].update();
particles[i].draw();
}
// 连接粒子
connectParticles();
requestAnimationFrame(animate);
}
// 事件监听
window.addEventListener('mousemove', (e) => {
mouse.x = e.x;
mouse.y = e.y;
});
window.addEventListener('mouseout', () => {
mouse.x = null;
mouse.y = null;
});
// 控制面板交互
const controlPanel = document.getElementById('controlPanel');
const togglePanel = document.getElementById('togglePanel');
const resetBtn = document.getElementById('resetBtn');
// 控制面板切换
togglePanel.addEventListener('click', () => {
controlPanel.classList.toggle('panel-hidden');
togglePanel.classList.toggle('rotated');
});
// 粒子数量控制
const particleCountSlider = document.getElementById('particleCount');
const particleCountValue = document.getElementById('particleCountValue');
particleCountSlider.addEventListener('input', () => {
particleCount = parseInt(particleCountSlider.value);
particleCountValue.textContent = particleCount;
init();
});
// 粒子速度控制
const particleSpeedSlider = document.getElementById('particleSpeed');
const particleSpeedValue = document.getElementById('particleSpeedValue');
particleSpeedSlider.addEventListener('input', () => {
particleSpeed = parseFloat(particleSpeedSlider.value);
particleSpeedValue.textContent = particleSpeed;
// 更新现有粒子的速度
particles.forEach(particle => {
const speedRatio = particleSpeed / parseFloat(particleSpeedSlider.previousValue || 1);
particle.speedX *= speedRatio;
particle.speedY *= speedRatio;
});
particleSpeedSlider.previousValue = particleSpeed;
});
// 连线距离控制
const connectionDistanceSlider = document.getElementById('connectionDistance');
const connectionDistanceValue = document.getElementById('connectionDistanceValue');
connectionDistanceSlider.addEventListener('input', () => {
connectionDistance = parseInt(connectionDistanceSlider.value);
connectionDistanceValue.textContent = connectionDistance;
});
// 鼠标引力控制
const mouseForceSlider = document.getElementById('mouseForce');
const mouseForceValue = document.getElementById('mouseForceValue');
mouseForceSlider.addEventListener('input', () => {
mouseForce = parseInt(mouseForceSlider.value);
mouseForceValue.textContent = mouseForce;
});
// 粒子大小控制
const particleSizeSlider = document.getElementById('particleSize');
const particleSizeValue = document.getElementById('particleSizeValue');
particleSizeSlider.addEventListener('input', () => {
particleSize = parseInt(particleSizeSlider.value);
particleSizeValue.textContent = particleSize;
// 更新现有粒子的大小
particles.forEach(particle => {
particle.size = particleSize;
});
});
// 主题颜色选择
const themeButtons = document.querySelectorAll('.theme-btn');
const themeColors = {
blue: ['#3B82F6', '#8B5CF6'],
pink: ['#EC4899', '#F472B6'],
green: ['#10B981', '#34D399'],
orange: ['#F59E0B', '#F97316'],
gray: ['#94A3B8', '#334155']
};
themeButtons.forEach(btn => {
btn.addEventListener('click', () => {
const theme = btn.getAttribute('data-theme');
[primaryColor, secondaryColor] = themeColors[theme];
// 更新粒子颜色
particles.forEach(particle => {
particle.color = primaryColor;
});
// 更新标题渐变
document.querySelector('h1').style.background = `linear-gradient(to right, ${primaryColor}, ${secondaryColor})`;
document.querySelector('h1').style.backgroundClip = 'text';
document.querySelector('h1').style.textDecorationColor = 'transparent';
});
});
// 重置按钮
resetBtn.addEventListener('click', () => {
particleCountSlider.value = 100;
particleSpeedSlider.value = 1;
connectionDistanceSlider.value = 150;
mouseForceSlider.value = 50;
particleSizeSlider.value = 2;
particleCountValue.textContent = 100;
particleSpeedValue.textContent = 1;
connectionDistanceValue.textContent = 150;
mouseForceValue.textContent = 50;
particleSizeValue.textContent = 2;
particleCount = 100;
particleSpeed = 1;
connectionDistance = 150;
mouseForce = 50;
particleSize = 2;
primaryColor = '#3B82F6';
secondaryColor = '#8B5CF6';
// 更新标题渐变
document.querySelector('h1').style.background = `linear-gradient(to right, ${primaryColor}, ${secondaryColor})`;
init();
});
// 初始化并启动动画
init();
animate();
</script>
</body>
</html>
创建一个.txt文本文件,把代码复制进去后保存,然后修改文本文件后缀为.html再打开即可。
发表评论