在 React 项目中实现小球动画

效果大概是这样的

ball

实现思路

总体思路

将小球封装成一个组件,这个组件有半径、移动速度、颜色等属性

然后再随机生成一堆小球

实际的代码

单个小球

这是一个类组件

Ball.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import React, { Component } from "react";
import "./Ball.css";
export default class Ball extends Component {
constructor(props) {
super(props);
this.state = {
radius: props.radius || 100,
left: props.left || 0, //横坐标
top: props.top || 0, //纵坐标
xSpeed: props.xSpeed, //X轴方向上的速度
ySpeed: props.ySpeed, //Y轴方向上的速度
bg: props.bg || "#f307", //背景颜色,如果没传默认为这个颜色
};
const duration = 16;
/*核心代码段 #start*/
setInterval(() => {
// 根据速度改变left和top
const xDis = (this.state.xSpeed * duration) / 1000; //间隔1s在X方向上移动的距离
const yDis = (this.state.ySpeed * duration) / 1000; //间隔1s在Y方向上移动的距离
let newLeft = this.state.left + xDis;
let newTop = this.state.top + yDis;
//当小球碰撞到视口左边缘
if (newLeft <= 0) {
newLeft = 0;
this.setState({
xSpeed: -this.state.xSpeed,
});
//当小球碰撞到视口右边缘
} else if (
newLeft >=
document.documentElement.clientWidth - this.state.radius
) {
newLeft = document.documentElement.clientWidth - this.state.radius;
this.setState({
xSpeed: -this.state.xSpeed,
});
}
//当小球碰撞到视口上边缘
if (newTop <= 0) {
newTop = 0;
this.setState({
ySpeed: -this.state.ySpeed,
});
//当小球碰撞到视口下边缘
} else if (
newTop >=
document.documentElement.clientHeight - this.state.radius
) {
newTop = document.documentElement.clientHeight - this.state.radius;
this.setState({
ySpeed: -this.state.ySpeed,
});
}
this.setState({
left: newLeft,
top: newTop,
});
}, duration);
/*核心代码段 #end*/
}
render() {
return (
<div
className="ball"
style={{
width: this.state.radius + "px",
height: this.state.radius + "px",
left: this.state.left + "px",
top: this.state.top + "px",
backgroundColor: this.state.bg,
}}
></div>
);
}
}

ps:这里 css 只加了 fixed 定位和圆角样式

这样就实现了一个小球在视口之内跳动

oneBall

最重要的这步完成了,然后就是生成一堆的小球了

这边也封装成了一个 List 类组件

BallList.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import React, { Component } from "react";
import Ball from "./Ball";
import { getRandomNumber } from "../utils/Random";
export default class BallList extends Component {
constructor(props) {
super(props);
this.state = {
ballInfos: [],
};
const interval = 1000;
const timer = setInterval(() => {
const info = {
radius: getRandomNumber(50, 200),
left: getRandomNumber(
0,
document.documentElement.clientWidth - this.radius
),
top: getRandomNumber(
0,
document.documentElement.clientHeight - this.radius
),
xSpeed: getRandomNumber(50, 500),
ySpeed: getRandomNumber(50, 500),
bg: `rgb(
${getRandomNumber(0, 255)},
${getRandomNumber(0, 255)},
${getRandomNumber(0, 255)})`,
};
this.setState({
ballInfos: [...this.state.ballInfos, info],
});
console.log(this.state.ballInfos.length);
if (this.state.ballInfos.length >= 15) clearInterval(timer);
}, interval);
}
render() {
const balls = this.state.ballInfos.map((item, i) => (
<Ball key={i} {...item} />
));
return <>{balls}</>;
}
}

这个里面用到的工具类就是一个获取随机数函数

1
2
3
export function getRandomNumber(min, max) {
return Math.floor(Math.random() * (max + 1 - min) + min);
}