<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Canvas碎纸屑闪烁动画特效</title>
<style>
body {
margin: 0;
padding: 0;
height: 100vh;
overflow: hidden;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
display: flex;
justify-content: center;
align-items: center;
font-family: Arial, sans-serif;
}
canvas {
display: block;
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
.content {
position: relative;
z-index: 2;
text-align: center;
color: white;
padding: 30px;
background: rgba(0, 0, 0, 0.3);
border-radius: 15px;
max-width: 80%;
}
h1 {
font-size: 3rem;
margin-bottom: 20px;
text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
}
p {
font-size: 1.2rem;
margin-bottom: 30px;
}
.btn {
padding: 12px 30px;
background: linear-gradient(45deg, #ff0a54, #ff477e);
color: white;
border: none;
border-radius: 50px;
font-size: 1.1rem;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 5px 15px rgba(255, 10, 84, 0.4);
}
.btn:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(255, 10, 84, 0.6);
}
.btn:active {
transform: translateY(0);
}
/* 版权信息 */
.footer {
position: absolute;
bottom: 20px;
right: 20px;
color: rgba(255, 255, 255, 0.5);
font-size: 12px;
z-index: 3;
}
.footer a {
color: #00f5d4;
text-decoration: none;
}
.footer a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<canvas id="confetti"></canvas>
<div class="content">
<h1>碎纸屑特效</h1>
<p>点击按钮触发炫酷的碎纸屑动画效果</p>
<button class="btn" id="triggerBtn">触发动画</button>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const canvas = document.getElementById('confetti');
const ctx = canvas.getContext('2d');
const triggerBtn = document.getElementById('triggerBtn');
// 设置画布大小为窗口大小
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
// 碎纸屑粒子类
class Particle {
constructor(x, y) {
this.x = x;
this.y = y;
this.size = Math.random() * 8 + 3;
this.density = Math.random() * 30 + 1;
this.color = this.getRandomColor();
this.velocityX = Math.random() * 5 - 2.5;
this.velocityY = Math.random() * 5 - 2.5;
this.rotation = Math.random() * 360;
this.rotationSpeed = Math.random() * 2 - 1;
this.opacity = 1;
this.fadeOut = false;
this.shape = Math.random() > 0.5 ? 'rect' : 'circle';
}
getRandomColor() {
const colors = [
'#ff0a54', '#ff477e', '#ff5c8a', '#ff7096',
'#ff85a1', '#f991b7', '#fbb1bd', '#f9bec7',
'#00f5d4', '#00bbf9', '#7bf1a8', '#9b5de5'
];
return colors[Math.floor(Math.random() * colors.length)];
}
update() {
this.velocityY += 0.1; // 重力
this.velocityX *= 0.99; // 空气阻力
this.velocityY *= 0.99;
this.x += this.velocityX;
this.y += this.velocityY;
this.rotation += this.rotationSpeed;
// 边界检测
if (this.y > canvas.height) {
this.velocityY *= -0.6; // 反弹
this.y = canvas.height;
}
if (this.fadeOut && this.opacity > 0) {
this.opacity -= 0.01;
}
}
draw() {
ctx.save();
ctx.globalAlpha = this.opacity;
ctx.translate(this.x, this.y);
ctx.rotate(this.rotation * Math.PI / 180);
if (this.shape === 'rect') {
ctx.fillStyle = this.color;
ctx.fillRect(-this.size/2, -this.size/2, this.size, this.size);
} else {
ctx.beginPath();
ctx.arc(0, 0, this.size/2, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
}
ctx.restore();
}
}
let particles = [];
let animationId = null;
let isAnimating = false;
// 创建碎纸屑
function createConfetti(x, y, count = 100) {
for (let i = 0; i < count; i++) {
particles.push(new Particle(x, y));
}
}
// 动画循环
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 更新和绘制所有粒子
for (let i = 0; i < particles.length; i++) {
particles[i].update();
particles[i].draw();
}
// 移除透明度为0的粒子
particles = particles.filter(p => p.opacity > 0);
// 如果还有粒子,继续动画
if (particles.length > 0) {
animationId = requestAnimationFrame(animate);
} else {
isAnimating = false;
triggerBtn.textContent = '触发动画';
}
}
// 触发动画
triggerBtn.addEventListener('click', function() {
if (isAnimating) {
// 如果正在动画,让所有粒子淡出
particles.forEach(p => p.fadeOut = true);
triggerBtn.textContent = '动画结束中...';
} else {
// 创建新粒子
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
createConfetti(centerX, centerY, 150);
isAnimating = true;
triggerBtn.textContent = '停止动画';
// 开始动画
if (!animationId) {
animate();
}
}
});
// 初始加载时自动触发一次
setTimeout(() => {
triggerBtn.click();
}, 500);
});
</script>
</body>
</html>