HTML粉色烟花秀

目录

系列文章

写在前面

完整代码

代码分析

写在最后


系列文章

|----|--------------------------------------------------------------------------------------------------------------|
| 序号 | 目录 |
| 1 | HTML满屏跳动的爱心(可写字) |
| 2 | HTML五彩缤纷的爱心 |
| 3 | HTML满屏漂浮爱心 |
| 4 | HTML情人节快乐 |
| 5 | HTML蓝色爱心射线 |
| 6 | HTML跳动的爱心(简易版) |
| 7 | HTML粒子爱心 |
| 8 | HTML蓝色动态爱心 |
| 9 | HTML跳动的爱心(双心版) |
| 10 | HTML橙色动态粒子爱心 |
| 11 | HTML旋转爱心 |
| 12 | HTML爱情树 |
| 13 | HTML3D相册 |
| 14 | HTML旋转相册 |
| 15 | HTML基础烟花秀 |
| 16 | HTML炫酷烟花秀 |
| 17 | HTML粉色烟花秀 |
| 18 | HTML新春烟花 |
| 19 | HTML龙年大吉 |
| 20 | HTML圣诞树 |
| 21 | HTML大雪纷飞 |
| 22 | HTML想见你 |
| 23 | HTML元素周期表 |
| 24 | HTML飞舞的花瓣 |
| 25 | HTML星空特效 |
| 26 | HTML黑客帝国字母雨 |
| 27 | HTML哆啦A梦 |
| 28 | HTML流星雨 |
| 29 | HTML沙漏爱心 |
| 30 | HTML爱心字母雨 |
| 31 | HTML爱心流星雨 |
| 32 | HTML生日蛋糕 |

写在前面

马上就要到2025年喽,博主用 html 给大家准备了粉色系的跨年烟花秀,一起来看看吧~

HTML(Hypertext Markup Language)是一种标记语言,用于创建网页的结构和内容。它使用一系列标签(tag)来标记文本,以指示浏览器如何展示内容。HTML是万维网的基础技术之一,它定义了网页的结构和链接方式。

HTML的发展可以追溯到1989年,由蒂姆·伯纳斯-李(Tim Berners-Lee)创始于欧洲核子研究组织(CERN)。最初,HTML只是用于将文档链接在一起,没有表现力很强。随着互联网的发展,HTML的功能逐渐增强,可以实现各种复杂的效果。

HTML由标签构成。标签通常用尖括号表示,例如<tag>。标签可以有属性(attribute),用于指定标签的属性值。属性通常包括名称和值,以键值对的形式表示。例如,<tag attribute="value">。

HTML文档通常由头部(head)和主体(body)组成。头部包含了文档的元信息,例如标题、样式表和脚本。主体包含了文档的实际内容,例如段落、标题、图像和链接。

HTML常用的标签和功能:

  1. 标题标签(<h1>到<h6>)用于定义标题的级别和重要性。

  2. 段落标签(<p>)用于定义段落。

  3. 链接标签(<a>)用于创建链接到其他网页或文件的超链接。

  4. 图像标签(<img>)用于在网页中插入图像。

  5. 列表标签(<ul>和<ol>)用于创建无序列表和有序列表。

  6. 表格标签(<table>、<tr>和<td>)用于创建表格。

  7. 表单标签(<form>、<input>和<button>)用于创建交互式表单。

  8. 样式标签(<style>)用于定义文档的样式。

  9. 脚本标签(<script>)用于在网页中嵌入JavaScript脚本。

除了这些基本功能外,HTML还支持更多的标签和功能,例如音频和视频播放、动画效果、地理定位等。此外,HTML还可以与CSS(层叠样式表)和JavaScript等技术一起使用,以实现更复杂和交互式的网页效果。

总结起来,HTML是一种用于创建网页结构和内容的标记语言。它使用标签来标记文本,并告诉浏览器如何展示内容。HTML的功能丰富多样,可以实现各种各样的网页效果。掌握HTML是学习Web开发的第一步。

完整代码

html 复制代码
<!DOCTYPE html>
<html lang="en">
<script>
  var _hmt = _hmt || [];
  (function () {
    var hm = document.createElement("script");
    hm.src = "https://hm.baidu.com/hm.js?c923daf3182a4b0ce01878475080aadc";
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(hm, s);
  })();
</script>

<head>
  <meta charset="UTF-8">
  <title>新年快乐!</title>
</head>
<style>
  body {
    margin: 0;
    overflow: hidden;
    background: black;
  }

  canvas {
    position: absolute;
  }
</style>

<body>

  <canvas></canvas>
  <canvas></canvas>
  <canvas></canvas>

  <script>

    function GetRequest() {
      var url = decodeURI(location.search);
      var theRequest = new Object();
      if (url.indexOf("?") != -1) {
        var str = url.substr(1);
        strs = str.split("&");
        for (var i = 0; i < strs.length; i++) {
          theRequest[strs[i].split("=")[0]] = unescape(strs[i].split("=")[1]);
        }
      }
      return theRequest;
    }
    class Shard {
      constructor(x, y, hue) {
        this.x = x;
        this.y = y;
        this.hue = hue;
        this.lightness = 50;
        this.size = 15 + Math.random() * 10;
        const angle = Math.random() * 2 * Math.PI;
        const blastSpeed = 1 + Math.random() * 6;
        this.xSpeed = Math.cos(angle) * blastSpeed;
        this.ySpeed = Math.sin(angle) * blastSpeed;
        this.target = getTarget();
        this.ttl = 100;
        this.timer = 0;
      }
      draw() {
        ctx2.fillStyle = `hsl(${this.hue}, 100%, ${this.lightness}%)`;
        ctx2.beginPath();
        ctx2.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
        ctx2.closePath();
        ctx2.fill();
      }
      update() {
        if (this.target) {
          const dx = this.target.x - this.x;
          const dy = this.target.y - this.y;
          const dist = Math.sqrt(dx * dx + dy * dy);
          const a = Math.atan2(dy, dx);
          const tx = Math.cos(a) * 5;
          const ty = Math.sin(a) * 5;
          this.size = lerp(this.size, 1.5, 0.05);

          if (dist < 5) {
            this.lightness = lerp(this.lightness, 100, 0.01);
            this.xSpeed = this.ySpeed = 0;
            this.x = lerp(this.x, this.target.x + fidelity / 2, 0.05);
            this.y = lerp(this.y, this.target.y + fidelity / 2, 0.05);
            this.timer += 1;
          } else
            if (dist < 10) {
              this.lightness = lerp(this.lightness, 100, 0.01);
              this.xSpeed = lerp(this.xSpeed, tx, 0.1);
              this.ySpeed = lerp(this.ySpeed, ty, 0.1);
              this.timer += 1;
            } else {
              this.xSpeed = lerp(this.xSpeed, tx, 0.02);
              this.ySpeed = lerp(this.ySpeed, ty, 0.02);
            }
        } else {
          this.ySpeed += 0.05;

          this.size = lerp(this.size, 1, 0.05);

          if (this.y > c2.height) {
            shards.forEach((shard, idx) => {
              if (shard === this) {
                shards.splice(idx, 1);
              }
            });
          }
        }
        this.x = this.x + this.xSpeed;
        this.y = this.y + this.ySpeed;
      }
    }

    class Rocket {
      constructor() {
        const quarterW = c2.width / 4;
        this.x = quarterW + Math.random() * (c2.width - quarterW);
        this.y = c2.height - 15;
        this.angle = Math.random() * Math.PI / 4 - Math.PI / 6;
        this.blastSpeed = 6 + Math.random() * 7;
        this.shardCount = 15 + Math.floor(Math.random() * 15);
        this.xSpeed = Math.sin(this.angle) * this.blastSpeed;
        this.ySpeed = -Math.cos(this.angle) * this.blastSpeed;
        this.hue = Math.floor(Math.random() * 360);
        this.trail = [];
      }
      draw() {
        ctx2.save();
        ctx2.translate(this.x, this.y);
        ctx2.rotate(Math.atan2(this.ySpeed, this.xSpeed) + Math.PI / 2);
        ctx2.fillStyle = `hsl(${this.hue}, 100%, 50%)`;
        ctx2.fillRect(0, 0, 5, 15);
        ctx2.restore();
      }
      update() {
        this.x = this.x + this.xSpeed;
        this.y = this.y + this.ySpeed;
        this.ySpeed += 0.1;
      }

      explode() {
        for (let i = 0; i < 70; i++) {
          shards.push(new Shard(this.x, this.y, this.hue));
        }
      }
    }

    console.log(GetRequest('val').val)

    const [c1, c2, c3] = document.querySelectorAll('canvas');
    const [ctx1, ctx2, ctx3] = [c1, c2, c3].map(c => c.getContext('2d'));
    let fontSize = 200;
    const rockets = [];
    const shards = [];
    const targets = [];
    const fidelity = 3;
    let counter = 0;
    c2.width = c3.width = window.innerWidth;
    c2.height = c3.height = window.innerHeight;
    ctx1.fillStyle = 'skyblue';
    const text = '新年快乐'
    let textWidth = 9999;

    while (textWidth > window.innerWidth) {
      ctx1.font = `900 ${fontSize--}px Arial`;
      textWidth = ctx1.measureText(text).width;
    }

    c1.width = textWidth;
    c1.height = fontSize * 1.5;
    ctx1.font = `900 ${fontSize}px Arial`;
    ctx1.fillText(text, 0, fontSize - 30);
    const imgData = ctx1.getImageData(0, 0, c1.width, c1.height);
    for (let i = 0, max = imgData.data.length; i < max; i += 4) {
      const alpha = imgData.data[i + 3];
      const x = Math.floor(i / 4) % imgData.width;
      const y = Math.floor(i / 4 / imgData.width);

      if (alpha && x % fidelity === 0 && y % fidelity === 0) {
        targets.push({ x, y });
      }
    }

    ctx3.fillStyle = 'pink';
    ctx3.shadowColor = 'pink';
    ctx3.shadowBlur = 25;


    (function loop() {
      ctx2.fillStyle = "deeppink";
      ctx2.fillRect(0, 0, c2.width, c2.height);
      counter += 1;

      if (counter % 15 === 0) {
        rockets.push(new Rocket());
      }
      rockets.forEach((r, i) => {
        r.draw();
        r.update();
        if (r.ySpeed > 0) {
          r.explode();
          rockets.splice(i, 1);
        }
      });

      shards.forEach((s, i) => {
        s.draw();
        s.update();

        if (s.timer >= s.ttl || s.lightness >= 99) {
          ctx3.fillRect(s.target.x, s.target.y, fidelity + 1, fidelity + 1);
          shards.splice(i, 1);
        }
      });

      requestAnimationFrame(loop);
    })();

    const lerp = (a, b, t) => Math.abs(b - a) > 0.1 ? a + t * (b - a) : b;

    function getTarget() {
      if (targets.length > 0) {
        const idx = Math.floor(Math.random() * targets.length);
        let { x, y } = targets[idx];
        targets.splice(idx, 1);

        x += c2.width / 2 - textWidth / 2;
        y += c2.height / 2 - fontSize / 2;

        return { x, y };
      }
    }
  </script>

</body>

</html>

修改文字

在代码的第185、186可以修改中间的文字颜色哦~

在代码的第191行可以修改背景颜色哦~

代码分析

这段代码通过HTML和JavaScript结合,创建了一个"新年快乐"主题的烟花动画,并在屏幕上显示文字"新年快乐"。其实现方式主要涉及画布(canvas)操作、火箭发射、烟花爆炸以及文字的动态生成与展示。以下是这段代码的详细分析。

一、代码结构概览

代码主要分为三部分:

  1. HTML结构 :通过<canvas>标签创建三个画布,用于不同的绘图操作。
  2. CSS样式:设置画布和页面的样式,使背景为黑色,并使画布覆盖整个页面。
  3. JavaScript逻辑:核心部分,负责烟花的发射、爆炸效果以及文字的生成。

二、画布的初始化与配置

在代码中,使用了三个canvas元素,它们通过JavaScript分别绑定到三个上下文对象:ctx1ctx2ctx3,用于不同的绘制操作。

  • ctx1:负责绘制"新年快乐"文字。
  • ctx2:负责绘制火箭的飞行和烟花的爆炸效果。
  • ctx3:用于绘制烟花爆炸后的残留效果。

这三个画布通过设置宽度和高度,确保其覆盖整个窗口。c1的宽高根据文字的宽度和字体大小动态调整,以确保文字能够适应屏幕。

三、文字的生成

代码通过ctx1.fillText方法在画布上绘制"新年快乐"文字。首先,代码根据屏幕的宽度动态调整字体大小,确保文字不会超出屏幕宽度。然后,getImageData方法获取画布上的像素数据,以提取出文字的形状。

通过逐个检查像素的透明度值(alpha),代码识别出文字中每个可见部分的坐标。接着,这些坐标存储在targets数组中,作为烟花爆炸的目标点。烟花爆炸后,碎片会逐渐飞向这些目标点,最终在屏幕上组成文字"新年快乐"。

四、烟花动画

烟花动画的核心是Rocket(火箭)和Shard(烟花碎片)两个类。

  • Rocket类 :代表烟花的发射过程。每个火箭有随机的初始位置和发射角度,沿着一条随机的轨迹上升。update方法用于更新火箭的位置,模拟火箭上升的运动;当火箭达到一定高度后,通过explode方法使其爆炸,生成多个Shard对象。
  • Shard类:代表烟花爆炸后的碎片。每个碎片有随机的速度和方向,在空中飞行并逐渐减速。碎片的目标是之前生成的文字的像素点,它们会逐渐朝着这些目标移动,直到到达目标点后停止。

在代码中,使用了requestAnimationFrame实现动画的平滑更新。loop函数是动画的主循环,在每一帧中都会更新火箭和碎片的位置,并重绘整个画布。

五、颜色和效果

在这段代码中,颜色的变化通过HSL色彩模型实现。每个火箭和烟花碎片都有一个随机的hue值,决定了它们的颜色。Shard类的draw方法使用ctx2.arc画圆的方法绘制每个碎片,并通过调整lightness值模拟烟花的逐渐消失效果。

此外,代码还通过shadowColorshadowBlur为爆炸后的烟花添加了阴影效果,使得爆炸显得更加闪亮逼真。

六、目标点与插值

碎片飞向文字目标点的过程使用了线性插值(lerp)算法,lerp函数用于在当前碎片位置与目标位置之间进行平滑过渡。通过不断缩小位置差距,碎片能够逐渐接近并最终停留在目标点。

七、火箭与碎片的生命周期

每个火箭和碎片都有各自的生命周期。当火箭上升到一定高度时,会自动触发爆炸,生成碎片。而每个碎片则在到达目标点或超过一定的存活时间后从数组中移除。这样可以避免画布上元素的无限增长,保证动画的性能和流畅度。

八、总结

这段代码通过使用HTML5的canvas元素,结合JavaScript中的对象和动画操作,实现了一个复杂而又美观的烟花动画。代码的核心思想是将烟花的爆炸与文字的显示相结合,通过计算每个像素点的位置,使烟花碎片能够精确地拼成文字。同时,代码还采用了多种动画技巧,如随机生成、插值算法和帧动画,确保动画的自然流畅。

写在最后

我是一只有趣的兔子,感谢你的喜欢!

相关推荐
燃先生._.5 分钟前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖1 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
唯之为之1 小时前
巧用mask属性创建一个纯CSS图标库
css·svg
m0_748235241 小时前
前端实现获取后端返回的文件流并下载
前端·状态模式
m0_748240252 小时前
前端如何检测用户登录状态是否过期
前端
black^sugar2 小时前
纯前端实现更新检测
开发语言·前端·javascript
寻找沙漠的人3 小时前
前端知识补充—CSS
前端·css
GISer_Jing3 小时前
2025前端面试热门题目——计算机网络篇
前端·计算机网络·面试
m0_748245523 小时前
吉利前端、AI面试
前端·面试·职场和发展