这段代码创建了一个具有动态烟花效果的页面,通过 JavaScript 和 canvas 技术实现了烟花的发射和爆炸效果,为页面添加了视觉吸引力和互动性。
大家复制代码时,可能会因格式转换出现错乱,导致样式失效。建议先少量复制代码进行测试,若未能解决问题,私信我,我会发送完整的压缩包给你
演示效果
HTML&CSS
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@100;200;300;400;500;600;700;800;900&display=swap"
rel="stylesheet">
<title>公众号关注:前端Hardy</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #222;
overflow: hidden;
}
:root {
--title: "Click Crazy Fireworks";
--author: "Matt Cannon";
--contact: "mc@mattcannon.design";
--description: "Random fireworks over a blank void, as is life. Click like crazy to see the finale!";
--keywords: "codepenchallenge, cpc-celebration, fireworks, animation, canvas, JavaScript, visual effects, celebration, night sky, particles, interactive, generative art, dynamic display, colorful explosions, seamless animations";
--last-modified: "2024-12-16";
--content-language: "en";
--generator: "HTML5, CSS3, JavaScript";
}
canvas {
display: block;
}
</style>
</head>
<body>
<script>
window.addEventListener("load", function () {
const canv = document.createElement("canvas");
canv.style.position = "absolute";
canv.style.top = "0";
canv.style.left = "0";
canv.style.width = "100%";
canv.style.height = "100%";
document.body.appendChild(canv);
const ctx = canv.getContext("2d");
let maxx = window.innerWidth;
let maxy = window.innerHeight;
canv.width = maxx;
canv.height = maxy;
window.addEventListener("resize", () => {
maxx = window.innerWidth;
maxy = window.innerHeight;
canv.width = maxx;
canv.height = maxy;
});
const rand = (min, max) => Math.random() * (max - min) + min;
const randInt = (min, max) => Math.floor(Math.random() * (max - min) + min);
const randColor = () => `hsl(${randInt(0, 360)}, 100%, 50%)`;
class Particle {
constructor(x, y, color, speed, direction, gravity, friction, size) {
this.x = x;
this.y = y;
this.color = color;
this.speed = speed;
this.direction = direction;
this.vx = Math.cos(direction) * speed;
this.vy = Math.sin(direction) * speed;
this.gravity = gravity;
this.friction = friction;
this.alpha = 1;
this.decay = rand(0.005, 0.02);
this.size = size;
}
update() {
this.vx *= this.friction;
this.vy *= this.friction;
this.vy += this.gravity;
this.x += this.vx;
this.y += this.vy;
this.alpha -= this.decay;
}
draw(ctx) {
ctx.save();
ctx.globalAlpha = this.alpha;
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
ctx.restore();
}
isAlive() {
return this.alpha > 0;
}
}
class Firework {
constructor(x, y, targetY, color, speed, size) {
this.x = x;
this.y = y;
this.targetY = targetY;
this.color = color;
this.speed = speed;
this.size = size;
this.angle = -Math.PI / 2 + rand(-0.3, 0.3);
this.vx = Math.cos(this.angle) * this.speed;
this.vy = Math.sin(this.angle) * this.speed;
this.trail = [];
this.trailLength = randInt(10, 25);
this.exploded = false;
}
update() {
this.trail.push({ x: this.x, y: this.y });
if (this.trail.length > this.trailLength) {
this.trail.shift();
}
this.x += this.vx;
this.y += this.vy;
this.vy += 0.02;
if (this.vy >= 0 || this.y <= this.targetY) {
this.explode();
return false;
}
return true;
}
explode() {
const numParticles = randInt(50, 150);
for (let i = 0; i < numParticles; i++) {
const angle = rand(0, Math.PI * 2);
const speed = rand(2, 7);
const particleSize = rand(1, 5);
explosions.push(
new Particle(
this.x,
this.y,
this.color,
speed,
angle,
0.05,
0.98,
particleSize
)
);
}
}
draw(ctx) {
ctx.save();
ctx.beginPath();
if (this.trail.length > 1) {
ctx.moveTo(this.trail[0].x, this.trail[0].y);
for (let point of this.trail) {
ctx.lineTo(point.x, point.y);
}
} else {
ctx.moveTo(this.x, this.y);
ctx.lineTo(this.x, this.y);
}
ctx.strokeStyle = this.color;
ctx.lineWidth = this.size;
ctx.lineCap = "round";
ctx.stroke();
ctx.restore();
}
}
let fireworks = [];
let explosions = [];
function launchFirework() {
const x = rand(maxx * 0.1, maxx * 0.9);
const y = maxy;
const targetY = rand(maxy * 0.1, maxy * 0.4);
const color = randColor();
const speed = rand(4, 8);
const size = rand(2, 5);
fireworks.push(new Firework(x, y, targetY, color, speed, size));
const timeout = rand(300, 800);
setTimeout(launchFirework, timeout);
}
launchFirework();
function animate() {
ctx.fillStyle = "rgba(0, 0, 0, 0.3)";
ctx.fillRect(0, 0, maxx, maxy);
for (let i = fireworks.length - 1; i >= 0; i--) {
const firework = fireworks[i];
if (!firework.update()) {
fireworks.splice(i, 1);
} else {
firework.draw(ctx);
}
}
for (let i = explosions.length - 1; i >= 0; i--) {
const particle = explosions[i];
particle.update();
if (particle.isAlive()) {
particle.draw(ctx);
} else {
explosions.splice(i, 1);
}
}
requestAnimationFrame(animate);
}
animate();
window.addEventListener("click", function (event) {
const x = event.clientX;
const y = maxy;
const targetY = event.clientY;
const color = randColor();
const speed = rand(4, 8);
const size = rand(2, 5);
fireworks.push(new Firework(x, y, targetY, color, speed, size));
});
});
</script>
</body>
</html>
CSS 样式
- *: 重置所有元素的边距、填充,设置 box-sizing 为 border-box,并统一字体为“Poppins”。
- body: 设置页面的显示方式、对齐方式、最小高度和背景色。
- canvas: 设置 canvas 元素的样式,使其覆盖整个屏幕。
JavaScript 部分
1、初始化 Canvas:
创建一个 canvas 元素,并将其添加到页面中。 设置 canvas 的宽度和高度为窗口的宽度和高度。 添加窗口大小调整事件监听器,以确保 canvas 大小随窗口变化。
2、定义辅助函数:
rand(min, max): 生成一个指定范围内的随机浮点数。 randInt(min, max): 生成一个指定范围内的随机整数。 randColor(): 生成一个随机的 HSL 颜色。
3、定义粒子类(Particle):
Particle 类表示一个粒子,具有位置、速度、颜色、重力、摩擦力、透明度等属性。 update()方法更新粒子的位置和透明度。 draw(ctx)方法在 canvas 上绘制粒子。 isAlive()方法检查粒子是否仍然可见。
4、定义烟花类(Firework):
Firework 类表示一个烟花,具有位置、目标高度、颜色、速度等属性。 update()方法更新烟花的位置,并检查是否到达目标高度。 explode()方法在烟花到达目标高度时生成爆炸效果,创建多个粒子。 draw(ctx)方法在 canvas 上绘制烟花的轨迹。
5、烟花和爆炸数组:
fireworks: 存储当前所有烟花的数组。 explosions: 存储当前所有爆炸粒子的数组。
6、发射烟花:
launchFirework()函数随机生成一个烟花,并设置一个定时器以随机时间间隔再次发射烟花。 页面加载时调用 launchFirework()函数。
7、动画循环:
animate()函数是动画的主循环,负责清除屏幕、更新和绘制所有烟花和爆炸粒子。 使用 requestAnimationFrame 实现循环。
8、用户交互:
添加点击事件监听器,用户点击屏幕时生成烟花。