背景
第一次看见这个效果,很惊艳,毕竟当时自己才算是刚入编程这个领域,也没有参加工作,对于编程了解的甚少,对于这种偏向于计算的东西更是了解甚少,对于当前而言,让我自己去讲数学知识与编程联系起来,也是一大难事,一点不参考的写出来,感觉也是个比较困难的事情。
今天能够分享出来,更多的也是慰藉一下,像当年我一样的人,喜欢这种,但是苦于网上没有资源,找了很久,不是vip就是需要收费,想去了解,被拒之于门外。
源码
将之封装为了vue组件还有js文件。有缘者自取。
JS源码
// 根据标签名称获取dom元素
function getElementFn(param) {
return document.getElementsByTagName(param)
}
// 返回指定属性名的属性值 (valD:默认值)
// 通过元素节点的属性名称获取属性的值
function getElementAttrFn(dom, key, valD) {
if (key == 'color') {
return valD
}
return dom.getAttribute(key) || valD
}
function getOptionsFn() {
var domData = getElementFn('script')
var dataLength = domData.length
var scriptDom = domData[dataLength - 1]
return {
tagLength: dataLength,
zIndex: getElementAttrFn(scriptDom, 'zIndex', -1), //层级
opacity: getElementAttrFn(scriptDom, 'opacity', 1), //透明度
color: getElementAttrFn(scriptDom, 'color', `rgb(${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)},${Math.floor(Math.random() * 255)})`), //颜色///没有感觉管用
count: getElementAttrFn(scriptDom, 'count', 100) //线条数量
}
}
// 获取canvas的宽高同时为canvas设置宽高
function getWidthOrHeight() {
;(canvasWidth = canvas.width =
window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth),
(canvasHeight = canvas.height =
window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight)
}
// 获取requestAnimationFrame方法
// 浏览器可以优化并行的动画动作,更合理的重新排列动作序列,并把能够合并的动作放在一个渲染周期内完成,从而呈现出更流畅的动画效果
function getRequestAnimationFrameFn() {
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
((callBack) => {
window.setTimeout(callBack, 1000 / 45)
})
)
}
function drawLineFn() {
clearCanvas()
randomPointList.forEach((item, index) => {
item.typeAX += item.typeBX
item.typeAY += item.typeBY
item.typeBX *= item.typeAX > canvasWidth || item.typeAX < 0 ? -1 : 1
item.typeBY *= item.typeAY > canvasHeight || item.typeAY < 0 ? -1 : 1
// 线段连接点
// contextObj.fillRect(item.typeAX - 2.5, item.typeAY - 2.5, 5, 5)
// 线段圆形连接点绘制
contextObj.fillStyle = styleOptions.color
contextObj.beginPath()
contextObj.arc(item.typeAX - 0.5, item.typeAY - 0.5, 2.5, 0, Math.PI * 2, true);
contextObj.closePath();
contextObj.fill();
for (let e = index + 1; e < randomOptions.length; e++) {
let randomOpItem = randomOptions[e]
if (randomOpItem.typeAX !== null && randomOpItem.typeAY !== null) {
// 两点横坐标差值
let diffX = item.typeAX - randomOpItem.typeAX
// 两点纵坐标差值
let diffY = item.typeAY - randomOpItem.typeAY
// 计算两点间线段的距离
let pointDis = diffX * diffX + diffY * diffY
if (pointDis < randomOpItem.max) {
if (randomOpItem == curMouseXY && pointDis >= randomOpItem.max / 2) {
item.typeAX -= 0.03 * diffX
item.typeAY -= 0.03 * diffY
}
let lineW = ((randomOpItem.max - pointDis) / randomOpItem.max)*1.5
contextObj.beginPath()
// 线宽
contextObj.lineWidth = lineW
contextObj.strokeStyle = styleOptions.color
contextObj.moveTo(item.typeAX, item.typeAY)
contextObj.lineTo(randomOpItem.typeAX, randomOpItem.typeAY)
contextObj.stroke()
}
}
}
})
var animationFn = getRequestAnimationFrameFn()
animationFn(drawLineFn)
}
// 清空画布
function clearCanvas() {
contextObj.clearRect(0, 0, canvasWidth, canvasHeight)
}
// 通过随机取值得到的参数位置
var randomOptions = []
// 当前鼠标位置
var curMouseXY = { typeAX: null, typeAY: null, max: 20000 }
// 获取线条的配置参数
var styleOptions = getOptionsFn()
console.log(styleOptions)
// canvas宽度
var canvasWidth = ''
// canvas高度
var canvasHeight = ''
// 创建canvas标签
var canvas = document.createElement('canvas')
// 获取context对象
var contextObj = canvas.getContext('2d')
// 为canvas设置id
canvas.id = `canvas${styleOptions.tagLength}`
// 为canvas设置style
canvas.style.cssText = `position:fixed;top:0;left:0;z-index:${styleOptions.zIndex};opacity:${styleOptions.opacity}`
// 将canvas插入body
var bodyDom = getElementFn('body')[0]
bodyDom.appendChild(canvas)
// 获取canvas的宽高同时为canvas设置宽高
getWidthOrHeight()
// 窗户变化重新获取宽高
window.onresize = getWidthOrHeight()
// 鼠标移动事件
window.onmousemove = function (event) {
event = event ? event : window.event
curMouseXY.typeAX = event.clientX
curMouseXY.typeAY = event.clientY
}
// 鼠标移出事件
window.onmouseout = function () {
curMouseXY.typeAX = null
curMouseXY.typeAY = null
}
// 随机组合点坐标
var randomPointList = []
for (f = 0; f < styleOptions.count; f++) {
randomPointList.push({
typeAX: Math.random() * canvasWidth,
typeAY: Math.random() * canvasHeight,
typeBX: 2 * Math.random() - 1,
typeBY: 2 * Math.random() - 1,
max: 40000 // 用来控制线段的长度
})
}
randomOptions = randomPointList.concat([curMouseXY])
setTimeout(function () {
drawLineFn()
}, 100)
vue 组件
<template>
<div class="lbg-wrapper">
<canvas id="canvasDom" class="canvas-dom"
>您的浏览器不支持canvas标签。</canvas
>
</div>
</template>
<script>
export default {
name: "loginBg",
data() {
return {
canWidth: "",
canHeight: "",
canvasDom: "",
contextObj: "",
styleOptions: {},
curMouseXY: { typeAX: null, typeAY: null, max: 40000 },
randomPointList: [],
randomOptions: [],
};
},
mounted() {
this.canvasDom = this.getEleByIdFn("canvasDom");
// 获取线条的配置参数
this.styleOptions = this.setOptionsFn();
// 获取context对象
this.contextObj = this.canvasDom.getContext("2d");
// 为canvas设置id
this.canvasDom.id = `canvas${this.styleOptions.tagLength}`;
// 为canvas设置style
this.canvasDom.style.cssText = `position:fixed;top:0;left:0;z-index:${this.styleOptions.zIndex};opacity:${this.styleOptions.opacity}`;
// 获取canvas的宽高同时为canvas设置宽高
this.getWidthOrHeight();
// 窗户变化重新获取宽高
window.onresize = this.getWidthOrHeight();
// 鼠标移动事件
window.onmousemove = (event)=> {
event = event ? event : window.event;
this.curMouseXY.typeAX = event.clientX;
this.curMouseXY.typeAY = event.clientY;
};
// 鼠标移出事件
window.onmouseout = ()=> {
this.curMouseXY.typeAX = null;
this.curMouseXY.typeAY = null;
};
// 随机组合点坐标
for (let f = 0; f < this.styleOptions.count; f++) {
this.randomPointList.push({
typeAX: Math.random() * this.canWidth,
typeAY: Math.random() * this.canHeight,
typeBX: 2 * Math.random() - 1,
typeBY: 2 * Math.random() - 1,
max: 20000, // 用来控制线段的长度
});
}
this.randomOptions = this.randomPointList.concat([this.curMouseXY]);
this.drawLineFn();
// setTimeout( ()=> {
// this.drawLineFn();
// }, 100);
},
methods: {
// 根据ID获取dom元素
getEleByIdFn(str) {
return document.getElementById(str);
},
// 获取指定元素的属性值
getEleAttrFn(dom, key, val) {
if (key === "color") {
return val;
}
return dom.getAttribute(key) || val;
},
// 设置配置项
setOptionsFn() {
return {
id: 1,
zIndex: 1, //层级
opacity: 1, //透明度
color: `rgb(${Math.floor(Math.random() * 255)},${Math.floor(
Math.random() * 255
)},${Math.floor(Math.random() * 255)})`, //颜色
count: 100, //线条数量
};
},
// 获取屏幕宽高
getWidthOrHeight() {
this.canWidth = this.canvasDom.width =
window.innerWidth ||
document.documentElement.clientWidth ||
document.body.clientWidth;
this.canHeight = this.canvasDom.height =
window.innerHeight ||
document.documentElement.clientHeight ||
document.body.clientHeight;
},
// 获取requestAnimationFrame方法
// 浏览器可以优化并行的动画动作,更合理的重新排列动作序列,并把能够合并的动作放在一个渲染周期内完成,从而呈现出更流畅的动画效果
getRequestAnimationFrameFn() {
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
((callBack) => {
window.setTimeout(callBack, 1000 / 45);
})
);
},
drawLineFn() {
this.clearCanvas();
this.randomPointList.forEach((item, index) => {
item.typeAX += item.typeBX;
item.typeAY += item.typeBY;
item.typeBX *= item.typeAX > this.canWidth || item.typeAX < 0 ? -1 : 1;
item.typeBY *= item.typeAY > this.canHeight || item.typeAY < 0 ? -1 : 1;
// 线段连接点
// this.contextObj.fillRect(item.typeAX - 2.5, item.typeAY - 2.5, 5, 5)
// 线段圆形连接点绘制
this.contextObj.fillStyle = this.styleOptions.color;
this.contextObj.beginPath();
this.contextObj.arc(
item.typeAX - 0.5,
item.typeAY - 0.5,
2.5,
0,
Math.PI * 2,
true
);
this.contextObj.closePath();
this.contextObj.fill();
for (let e = index + 1; e < this.randomOptions.length; e++) {
let randomOpItem = this.randomOptions[e];
if (randomOpItem.typeAX !== null && randomOpItem.typeAY !== null) {
// 两点横坐标差值
let diffX = item.typeAX - randomOpItem.typeAX;
// 两点纵坐标差值
let diffY = item.typeAY - randomOpItem.typeAY;
// 计算两点间线段的距离
let pointDis = diffX * diffX + diffY * diffY;
if (pointDis < randomOpItem.max) {
if (
randomOpItem == this.curMouseXY &&
pointDis >= randomOpItem.max / 2
) {
item.typeAX -= 0.03 * diffX;
item.typeAY -= 0.03 * diffY;
}
let lineW =
((randomOpItem.max - pointDis) / randomOpItem.max) * 1;
this.contextObj.beginPath();
// 线宽
this.contextObj.lineWidth = lineW;
this.contextObj.strokeStyle = this.styleOptions.color;
this.contextObj.moveTo(item.typeAX, item.typeAY);
this.contextObj.lineTo(randomOpItem.typeAX, randomOpItem.typeAY);
this.contextObj.stroke();
}
}
}
});
var animationFn = this.getRequestAnimationFrameFn();
animationFn(this.drawLineFn);
},
// 清空画布
clearCanvas() {
this.contextObj.clearRect(0, 0, this.canWidth, this.canHeight);
},
},
};
</script>
<style lang="scss" scoped>
.lbg-wrapper{
box-sizing: border-box;
position: relative;
width: 100%;
height: 100%;
}</style>