文章目录

    • 一、前言
    • 二、创意名
    • 三、效果展示
    • 四、烟花代码
    • 五、总结

一、前言

2022年圣诞节到来啦,圣诞节是基督教纪念耶稣诞生的重要节日。亦称耶稣圣诞节、主降生节,天主教亦称耶稣圣诞瞻礼。耶稣诞生的日期,《圣经》并无记载。公元336年罗马教会开始在12月25日过此节。12月25日原是罗马帝国规定的太阳神诞辰。有人认为选择这天庆祝圣诞,是因为基督教徒认为耶稣就是正义、永恒的太阳。5世纪中叶以后,圣诞节作为重要节日,成了教会的传统,并在东西派教会中逐渐传开。因所用历法不同等原因,各教派会举行庆祝的具体日期和活动形式也有差别。圣诞节习俗传播到亚洲主要是在十九世纪中叶,日本、韩国等都受到了圣诞文化的影响。现在西方在圣诞节常互赠礼物,举行欢宴,并以圣诞老人、圣诞树等增添节日气氛,已成为普遍习俗。圣诞节也成为西方世界以及其他很多地区的公共假日。

二、创意名

圣诞节就要到了,本篇我们将用html+js写一个动态的烟花代码,程序员的浪漫这不就来了吗,感兴趣的小伙伴可下载学习,安静的在家中读懂它的那一刻,在这疫情肆虐的日子里也是一件很不错的事,将有趣的东西分享给你,希望你度过一个愉快的圣诞节!

三、效果展示

基础版动画效果,有声音


进阶版动画效果,可点击绽放烟花

四、烟花代码

动画主要由焰火类,背景图和随机函数等组成。进阶版可点击屏幕直接开始绽放烟花。
以下是HTML部分,完整代码及效果点击下载烟花代码
进阶版烟花代码2

<!doctype html><html><head>    <meta charset="utf-8">    <title>动态烟花代码</title>    <style>        html,        * {            margin: 0;            padding: 0        }        body {            background-image: url(bg.png);            background-size: 100% 100%;            background-size: 100%;             background-repeat:no-repeat;        }        .demo {            margin: 0 auto;            width: 100%;            height: 100%;        }        h1 {            margin: 150px auto 30px auto;            text-align: center;            font-family: 'Roboto';        }    </style></head><body>    <div class="demo">    </div>    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>    <script src="fireworks.js"></script>    <script>        $('.demo').fireworks({            sound: true,            opacity: 0.6,            width: '100%',            height: '100%'        });    </script></body></html>

js部分

// 焰火集合类class Fireworks {    _timer = null    _animater = null    _useAnimationFrame = true        ctx = null // 画布上下文,都画这上面    offScreenCtx = null // 离屏 canvas,优化性能    fps = 60 // 帧率控制    fireworks = [] // 焰火数组    fireworkCount = 8 // 焰火数量    fireworkInterval = 400 // 焰火爆炸间隔    fireworkColors = DEFAULT_COLORS // 焰火颜色随机取值数组    particleOptions = { // 粒子配置      size: 15, // 几块钱的烟花      speed: 15, // 燃烧的速度      gravity: 0.08, //  地球的引力,向下的      power: 0.93, // 动力,值越大冲越远      shrink: 0.97, // 燃料消耗的速度      jitter: 1, // 摇摇晃摇      color: 'hsla(210, 100%, 50%, 1)', // 颜色    }      constructor(dom, options = {}) {      if (!(dom instanceof HTMLElement)) {        options = dom || {}      }        if (!dom) {        dom = document.body      }        this.initCanvas(dom)        const { particleOptions = {}, ...others } = options      this.particleOptions = { ...this.particleOptions, ...particleOptions }      Object.keys(others).forEach(key => this[key] = others[key])        this._useAnimationFrame = this.fps >= 60    }      // 初始化画布    initCanvas(dom) {      let canvas = dom        const isCanvas = canvas.nodeName.toLowerCase() === 'canvas'      if (!isCanvas) {        canvas = document.createElement('canvas')        dom.appendChild(canvas)      }        const { width, height } = dom.getBoundingClientRect()      canvas.width = width      canvas.height = height      canvas.style.cssText = `width: ${width}px; height: ${height}px;`        this.ctx = canvas.getContext('2d')        const offScreenCanvas = canvas.cloneNode()      this.offScreenCtx = offScreenCanvas.getContext('2d')    }      // 创建单个焰火    createFirework(x, y, color) {      const { ctx, particleOptions, fireworkColors } = this      const { width, height } = ctx.canvas      x = x ?? random(width * 0.1, width * 0.9)      y = y ?? random(height * 0.1, height * 0.9)      color = color ?? random(fireworkColors)      const particleCount = random(80, 100)        const firework = new Firework({ particleOptions, particleCount, x, y, color })      this.fireworks.push(firework)    }      // 焰火燃尽,无情灭之    checkFireworks() {      this.fireworks = this.fireworks.filter(firework => !firework.isBurnOff())    }      // 检查是否需要创建焰火    loop() {      let interval = this.fireworkInterval * random(0.5, 1)      this._timer = setTimeout(() => {        this.checkFireworks()          if (this.fireworks.length < this.fireworkCount) {          this.createFirework()        }          this.loop()      }, interval)    }      // 绘制焰火    render(animationFunction, interval) {      this._animater = animationFunction(() => {        const { width, height } = this.ctx.canvas          // 通过绘制黑色透明图层,达到尾焰的效果        this.ctx.fillStyle = 'rgba(0, 0, 0, 0.05)'        this.ctx.fillRect(0, 0, width, height)                this.offScreenCtx.clearRect(0, 0, width, height)          this.fireworks.forEach(firework => {          firework.render(this.offScreenCtx)        })          this.ctx.save()        this.ctx.globalCompositeOperation = 'lighter'        this.ctx.drawImage(this.offScreenCtx.canvas, 0, 0, width, height)        this.ctx.restore()          this.render(animationFunction, interval)      }, interval)    }      // 前进四 !!!    start() {      this.loop()      // 60 帧就用 requestAnimationFrame,否则用 setTimeout      const animationFunction = this._useAnimationFrame ? requestAnimationFrame : setTimeout      const interval = 16.67 * (60 / this.fps)      this.render(animationFunction, interval)    }      // 休息一下    pause() {      this._timer && clearTimeout(this._timer)      this._animater && (this._useAnimationFrame ? cancelAnimationFrame(this._animater)        : clearTimeout(this._animater))        this._timer = null      this._animater = null    }      // 结束吧这个世界    stop() {      this.pause()        this.fireworks.length = 0        const { width, height } = this.ctx.canvas()      this.ctx.clearRect(0, 0, width, height)    }  }    // 焰火类  class Firework {    _status = STATUS.INIT      x = 0    y = 0      color = 'rgba(255, 255, 255, 1)'    particleCount = 80    particles = []    particleOptions = {}      constructor(options = {}) {      Object.keys(options).forEach(key => this[key] = options[key])      this._status = STATUS.INIT        this.initParticles()    }      // 初始化粒子    initParticles() {      const { x, y, color, particleOptions } = this      const { size: baseSize } = particleOptions        for (let index = 0; index < this.particleCount; index++) {        const size = random(-baseSize / 2, baseSize / 2) + baseSize        const particle = new Particle({ ...particleOptions, x, y, size, color })        this.particles.push(particle)      }    }      // 更新粒子    updateParticles() {      this.particles.forEach(particle => particle.update())        this.particles = this.particles.filter(particle => !particle.isBurnOff())         // 拥有的粒子都燃尽了,自己也就结束了      if (this.particles.length === 0) {        this._status = STATUS.COMPLETED      }    }      // 渲染粒子    render(ctx) {      this.updateParticles()      if (this.isBurnOff()) return        this.particles.forEach(particle => {        particle.render(ctx)      })    }      isBurnOff() {      return this._status === STATUS.COMPLETED    }  }    // 焰火粒子类  class Particle {    size = 10    speed = 15    gravity = 0.2    power = 0.92    shrink = 0.93    jitter = 0.08    color = 'hsla(210, 100%, 50%, 1)'    shadowColor = 'hsla(210, 100%, 50%, 0.1)'      x = 0 // x 坐标位置    y = 0 // y 坐标位置      vel = { // 速度      x: 0,      y: 0,    }      constructor(options) {      Object.keys(options).forEach(key => {        this[key] = options[key]      })      const angle = random(0, Math.PI * 2)      const speed = Math.cos(random(0, Math.PI / 2)) * this.speed      this.vel = {        x: Math.cos(angle) * speed,        y: Math.sin(angle) * speed,      }      this.shadowColor = tinycolor(this.color).setAlpha(0.1)    }      // 移形换位    update() {      this.vel.x *= this.power      this.vel.y *= this.power        this.vel.y += this.gravity        const jitter = random(-1, 1) * this.jitter      this.x += this.vel.x + jitter      this.y += this.vel.y + jitter        this.size *= this.shrink    }      // 绘制单粒子    render(ctx) {      if (this.isBurnOff()) return        ctx.save()        const { x, y, size, color, shadowColor } = this      // 红里透白,像极了爱情      const gradient = ctx.createRadialGradient(x, y, 0, x, y, size / 2)      gradient.addColorStop(0.1, 'rgba(255, 255, 255, 0.3)')      gradient.addColorStop(0.6, color)      gradient.addColorStop(1, shadowColor)        ctx.fillStyle = gradient        // ctx.beginPath()      // ctx.arc(x, y, size, 0, Math.PI * 2, true)      // ctx.closePath()      // ctx.fill()        // 绘制矩形性能更好      ctx.fillRect(x, y, size, size)        ctx.restore()    }      // 小到看不到    isBurnOff() {      return this.size < 1    }  }

五、总结

圣诞节,玲儿响,温情祝福传递忙;喜盛宴,披红装,圣诞金娃送吉祥;夜月美,心儿醉,吉祥安康永相随;平安夜,送平安,幸福快乐人变美。最后,祝所有和我一样即将考研的人旗开得胜,坚持就是胜利,世上无难事,只要肯攀登。