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端左下角的音乐播放功能我又给加回来了,没有它总感觉还是少了点什么。