起源:为项目的403,404,500等页面添加背景,使页面更加生动有趣,下面开始讲流程吧。
技术栈:react + canvas + html + css
HTML 部份
<div className={bg.pageBg}>
<canvas ref={this.canvas}></canvas>
</div>
CSS 部份
.pageBg{
margin: 0;
padding:0;
height: cale(100vh - 40px);
position: absolute;
z-index: -1;
cursor:none;
overflow: hidden;
background: #ffffff;
}
JS 部份
定义属性和初始值
//画布属性 let canvas="", ctx="", //鼠标移动的属性 mouseMoving= false, mouseMoveChecked= "", mouseX= 0, mouseY= 0, //存放线条 dots= [], minDotsCo= 2, maxDotsCu= 50, //存放圆圈 points= [], initPoints= 80;
新建两个构造函数分别用于承载 线条 和 圆圈
- 圆圈 ```jsx class Points{ constructor(id, x, y) { this.id = id; this.x = x; this.y = y; this.r = Math.floor(Math.random() 5) + 1; let opacity = (Math.floor(Math.random() 10) + 1) / 10 / 2; this.color = “rgba(192,192,192,” + opacity + “)”; } draw = ()=>{ ctx.fillStyle = this.color; ctx.shadowBlur = this.r 2; ctx.beginPath(); ctx.arc(this.x, this.y, this.r, 0, 2 Math.PI, false); ctx.closePath(); ctx.fill(); }; move = ()=>{ this.y -= .15; if (this.y <= -10) this.y = canvas.height + 10; this.draw(); }
}
- 线条
```jsx
class Dot{
constructor(id, x, y) {
this.id = id;
this.x = x;
this.y = y;
this.r = Math.floor(Math.random() *5) + 1;
this.speed = .5;
this.opacity = .5;
//255,105,180
this.color = "rgba(220,220,220," + this.opacity + ")";
this.linkColor = "rgba(220,220,220," + this.opacity/4 + ")";
this.dir = Math.floor(Math.random() *140) + 200;
}
draw = ()=>{
ctx.fillStyle = this.color;
ctx.shadowBlur = this.r * 2;
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI, false);
ctx.closePath();
ctx.fill();
}
link = ()=>{
if(this.id ==0) return;
let pd1 = getPreDot(this.id, 1),
pd2 = getPreDot(this.id, 2),
pd3 = getPreDot(this.id, 3);
if (!pd1) return;
ctx.strokeStyle = this.linkColor;
ctx.moveTo(pd1.x, pd1.y);
ctx.beginPath();
ctx.lineTo(this.x, this.y);
if(pd2 !=false) ctx.lineTo(pd2.x, pd2.y);
if(pd3 !=false) ctx.lineTo(pd3.x, pd3.y);
ctx.stroke();
ctx.closePath();
}
move = ()=>{
this.opacity -= 0.005;
if(this.opacity <= 0){
this.die();
return;
}
this.color = "rgba(220,220,220," + this.opacity +")";
this.linkColor = "rgba(220,220,220," + this.opacity/4 + ")";
this.x = this.x + Math.cos(this.dir * (Math.PI / 180)) * this.speed;
this.y = this.y + Math.sin( this.dir* (Math.PI / 180)) * this.speed;
this.draw();
this.link();
}
die = ()=>{
dots[this.id] = null;
delete dots[this.id]
}
}
function getPreDot(id, step1){
if (id == 0 || id - step1 < 0) return false;
if (typeof dots[id - step1] != "undefined") return dots[id - step1];
else return false;
}
以上为圆圈和线条的构造函数,也可以把他们看做一个圆圈和一个线条的生命周期,当透明度opacity <=0是会触发die周期函数,不过这里我们想要圆圈一直存在则就不需要die周期函数,在鼠标移动期间会产生线条,然后逐渐消失。
在react的挂载周期开始初始化
记得在componentWillMount时移除监听事件
componentDidMount() {
canvas = this.canvas.current; //document.getElementById("canvas");
ctx = canvas.getContext("2d");
this.resize();
this.init();
window.addEventListener("resize", this.resize);
window.addEventListener("mousemove", this.onmousemove);
}
resize = ()=>{
canvas.width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
canvas.height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
};
init = ()=>{
let width = canvas.width,
height = canvas.height;
ctx.strokeStyle = "#FFFFFF";
ctx.shadowColor = "#FFFFFF";
for (let i = 0; i < initPoints; i++) {
points[i] = new Points(i, Math.floor(Math.random() * width),Math.floor(Math.random() * height));
}
ctx.shadowBlur = 0;
this.animate();
}
执行动画的方法写在animate里面,requestAnimationFrame请求动画帧
animate= ()=>{
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i in points) {
points[i].move();
}
for (let i in dots) {
dots[i].move();
}
this.drawIfMouseMoving();
requestAnimationFrame(this.animate);
};
drawIfMouseMoving 该方法用于在鼠标移动计算鼠标的位移差
drawIfMouseMoving = ()=>{
if(!mouseMoving) return false;
if(dots.length ==0){
dots[0] = new Dot(0, mouseX, mouseY);
dots[0].draw();
return false;
}
let preDot = getPreDot(dots.length, 1),
prevX = preDot.x,
prevY = preDot.y,
diffX = Math.abs(prevX - mouseX),
diffY = Math.abs(prevY - mouseY);
if(diffX < minDotsCo || diffY < minDotsCo) return false;
let xChange = Math.random() > .5 ? -1 :1;
xChange = xChange * Math.floor(Math.random() * maxDotsCu) + 1;
let yChange = Math.random() > .5 ? -1 : 1;
yChange = yChange * Math.floor(Math.random() * maxDotsCu) + 1;
dots[dots.length] = new Dot(dots.length, mouseX + xChange, mouseY + yChange);
dots[dots.length - 1].draw();
dots[dots.length - 1].link();
};