网页背景添加粒子飘动效果

前往原站点查看

2023-11-28 14:36:43

    对于首页粒子飘动的效果,我其实早在一年前就有计划去实现,只是不知怎得遂竟忘之。近来重构部分页面样式时,才发现了这样一个空函数 bkeffectStart 藏匿于代码之中,宛如空头支票,欺骗了我许久。

    话不多说,先上结果图(下图所示)。可以看到一个个小的圆点在到处飘动(静态图片怎么看出来的2333,[假装在动.gif]),鼠标滑过的地方,附近的点会自动连出一条线来。



    原理是依据canvas绘图实现的,有参考CSDN博主 ღ冷风20°C᭄ꦿ࿐ 的博客文章: Canvas实现网页星空背景粒子动效跟随光标。然后加以适当的修改与封装以适应我这个vue的网站。

    首先对需要展示该效果的页面添加一个canvas容器,要独立显示在整个页面上。采用fixed定位模式,可以设置z-index来设置与其他层的层次关系,我这边这些粒子会在导航栏的下面一层显示。

<div style="position: fixed;z-index: 50;top:0">
  <canvas id="myCanvas"></canvas>
</div>

    下面是我简单封装的一个背景效果js代码:

/*
  代码有参考其他博客,并且进一步改编,以适应接入当前的vue脚手架
  原参考博客(作者:ღ冷风20°C᭄ꦿ࿐):
  https://blog.csdn.net/weixin_50241387/article/details/125038394
*/

// canvas 容器
var canvas
// 绘图上下文
var ctx
// 存储所有的小球
var balls = []

// 记录鼠标移动时的mouseX坐标
var mouseX
var mouseY

// 基础配置
var basicConfig = {
  dotLineD: false,
  mouseLineD: false,
  randomColor: false,
  maxR: 1
}

/**
 * 开启特效
 * @param {boolean} dotLineD 是否自动对点进行连线,默认false
 * @param {boolean} mouseLineD 是否跟踪鼠标连线, 默认true
 * @param {boolean} randomColor 是否颜色随机,默认false
 * @param {number} maxR 最大的点半径大小,默认1
 */
function bkeffectStart (dotLineD = false, mouseLineD = true, randomColor = false, maxR = 1) {
  // 初始化基础配置 basicConfig
  basicConfig.dotLineD = dotLineD
  basicConfig.mouseLineD = mouseLineD
  basicConfig.randomColor = randomColor
  basicConfig.maxR = maxR

  // 初始化 canvas 与 ctx
  canvas = document.getElementById('myCanvas')
  canvas.width = window.innerWidth
  canvas.height = window.innerHeight
  ctx = canvas.getContext('2d')

  // canvas监听鼠标移动事件
  canvas.onmousemove = function (e) {
    mouseX = e.offsetX
    mouseY = e.offsetY
  }

  // 当容器中不存在球时,说明是第一次调用,初始化球参到 balls 集合中
  if (balls.length === 0) {
    // 创建100个小球
    for (var i = 0; i < 500; i++) {
      var ball = new Ball()
      balls.push(ball)
    }
    // 开始绘制 (注意不要写在这个if的外面,否则会越来越快的哦)
    main()
    console.log('首页背景动效装载完毕 -- dreamcenter')
  }
}

// 窗口改变时修改画布大小
window.onresize = function () {
  canvas.width = window.innerWidth
  canvas.height = window.innerHeight
}

// 创建小球的构造函数
function Ball () {
  // 横纵坐标
  this.x = randomNum(3, canvas.width - 3)
  this.y = randomNum(3, canvas.height - 3)
  // 半径
  this.r = randomNum(1, basicConfig.maxR)
  // 颜色
  this.color = basicConfig.randomColor ? randomColor() : '#CFECE6'
  // 平移速度,正负区间是为了移动方向的多样性
  this.speedX = randomNum(-3, 3) * 0.1
  this.speedY = randomNum(-3, 3) * 0.1
}
Ball.prototype = {
  // 绘制小球
  draw: function () {
    ctx.beginPath()
    ctx.globalAlpha = 1
    ctx.fillStyle = this.color
    ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2)
    ctx.fill()
  },
  // 小球移动
  move: function () {
    this.x += this.speedX
    this.y += this.speedY
    // 为了合理性,设置极限值(判断边界值,让圆球始终保证在画面内)
    if (this.x <= 3 || this.x > canvas.width - 3) {
      this.speedX *= -1
    }
    if (this.y <= 3 || this.y >= canvas.height - 3) {
      this.speedY *= -1
    }
  }
}

// 主要绘制帧
function main () {
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  // 鼠标移动绘制线
  if (basicConfig.mouseLineD) {
    mouseLine()
  }
  // 小球与小球之间自动画线
  drawLine()
  // 使用关键帧动画,不断的绘制和清除
  window.requestAnimationFrame(main)
}

// 画点与连线
function drawLine () {
  for (var i = 0; i < balls.length; i++) {
    balls[i].draw()
    balls[i].move()
    for (var j = 0; j < balls.length; j++) {
      if (i !== j) {
        if (srss(balls[i].x - balls[j].x, balls[i].y - balls[j].y) < 80 && basicConfig.dotLineD) {
          ctx.beginPath()
          ctx.moveTo(balls[i].x, balls[i].y)
          ctx.lineTo(balls[j].x, balls[j].y)
          ctx.strokeStyle = '#CFECE6'
          ctx.globalAlpha = 0.2
          ctx.stroke()
        }
      }
    }
  }
}
// 使用鼠标移动划线
function mouseLine () {
  for (var i = 0; i < balls.length; i++) {
    if (srss(balls[i].x - mouseX, balls[i].y - mouseY) < 80) {
      ctx.beginPath()
      ctx.moveTo(balls[i].x, balls[i].y)
      ctx.lineTo(mouseX, mouseY)
      ctx.strokeStyle = 'white'
      ctx.globalAlpha = 0.8
      ctx.stroke()
    }
  }
}
// 随机函数
function randomNum (m, n) {
  return Math.floor(Math.random() * (n - m + 1) + m)
}
// 平方和开方
function srss (a, b) {
  return Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2))
}
// 随机颜色
function randomColor () {
  return 'rgb(' + randomNum(0, 255) + ',' + randomNum(0, 255) + ',' + randomNum(0, 255) + ')'
}

export { bkeffectStart }

    应该还是比较容易理解的吧。基本思路就是:

初始化配置->初始化容器->初始化小球/点->开始绘制(清空画布->绘制鼠标连线->绘制小球与连线->同步浏览器刷新率刷新)。

    接着就是在页面引入该js文件了。所有的参数都有一个默认值,调用bkeffectStart()即可达成效果。当然如果启用其他效果传递相应的参数即可。如小球之间是否自动连线、是否启用鼠标连线、小球颜色是否随机、小球最大半径等等,都可以设置 bkeffectStart (dotLineD = false, mouseLineD = true, randomColor = false, maxR = 1)

<script>
import { bkeffectStart } from '../js/bkeffect'
export default {
  mounted () {
    bkeffectStart()
  }
}
</script>


    完。


    ps:近日在重新修改个人主站的部分页面样式,不过对于主研后端的我来说,风格样式的创新思路几近枯竭。当然可能改的好看了,也有可能越改越丑(),一切取决于当日的精神状态( ̄y▽, ̄)╭ 。外加上早期从零建站代码混乱(定位乱飞),样式作用域错综复杂(改一处样式整个页面样式都混乱了),还有依靠bug存在的样式(友链页左边友人志那块)等等,大改还是挺刺激的一件事情。虽说早就想改评论模块了,但是事实是,根本改不动,比我预想的要麻烦许多~


    ps2:pc端左下角的音乐播放功能我又给加回来了,没有它总感觉还是少了点什么。



上一篇: 调用支付宝账单接口记账
下一篇: 联机围棋的简单实现