新主题的背景在大屏状态下是属于有点单调一点,单栏的情况下结合短宽的情况下看起是空旷了些,想着给后面加一个背景,暂时没想好怎么换,不过夜间模式的情况下还是,想弄出一点不一样的效果,于是想到星光的闪烁的画面,觉得是不错的思路,刚好看到有一位 博主Jdeal 的站点也有类似的效果,想做差不多就可以了,看了一下源码是用多个 div 生成的效果,再加上 css 配合颜色和动画,这样做虽然可以,但是会有很多无效元素在页面上,我的强迫症还是决定用 canvas 重写一个,所有动画都在里面执行,需要注意的几点如下:

  1. 随机生成大小不超过3像素的圆点,随机透明度,随机位置。
  2. 圆点整体向上运动,速度随机,角度随机。
  3. 移动的过程中有圆点的透明度会持续衰弱为0

大致就是如下效果。

sky

根据需求,下面开始写代码。

创建 Canvas 元素并获取上下文

var canvas = document.getElementById('myCanvas')
var ctx = canvas.getContext('2d')

设置 Canvas 的宽度和高度

canvas.width = window.innerWidth
canvas.height = window.innerHeight
// 创建一个包含萤火光点信息的数组
var sparks = []

生成圆点

function createSpark() {
  const x = Math.random() * canvas.width
  const y = Math.random() * canvas.height // 从底部开始
  const radius = Math.random() * 1 + 1
  const opacity = Math.random() * .5 + .5

  sparks.push({
    x: x,
    y: y,
    radius: radius,
    opacity: opacity,
    blinkCount: 0,
    speedX: (Math.random() - .5) * 2,
    speedY: -Math.random() * .1 - .5, // 向上移动,上升速度减小
    angle: Math.random() * Math.PI * 2, // 初始角度随机
    angularSpeed: Math.random() * .1 - .05 // 角速度随机增大
  })
}

更新圆点的位置,并绘制到 Canvas 上

function updateSparks() {
  for (let i = 0; i < sparks.length; i++) {
    const spark = sparks[i]

    spark.x += spark.speedX
    spark.y += spark.speedY
    spark.angle += spark.angularSpeed

    // 左右摆动效果
    spark.x += Math.sin(spark.angle) * .1
    
    if (spark.opacity <= 0) {
      sparks.splice(i, 1)
      i--
      continue
    }

    spark.opacity -= 0.01;

    ctx.beginPath()
    ctx.arc(spark.x, spark.y, spark.radius, 0, Math.PI * 2)
    ctx.fillStyle = `rgba(255, 255, 255, ${spark.opacity})`
    ctx.fill()
  }
}

使用 requestAnimationFrame 实现动画效果

function animate() {
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  if (sparks.length < 10) {
    createSpark()
  }
  updateSparks()
  requestAnimationFrame(animate)
}
// 启动动画
animate()

大功告成,可以效果可以看一下本站的夜间模式效果,虽然丑了点(又不是不能用!)