本文原创地址链接:http://blog.csdn.net/zhou_xiao_cheng/article/details/53887587,未经博主允许不得转载。
前一段时间用React实现了一些很好玩的功能,写成博客,与大家一起分享。在这一篇博客里,我将会介绍如何使用React实现小球移动、在与屏幕边缘发生碰撞后弹开的效果。
利用CSS简单绘制小球
ColorBall.js:
import React, { Component } from 'react';
class ColorBall extends Component {
render () {
const style = {
width: '50px',
borderWidth: '10px',
borderColor: '#0094FF'
}
return (
<div className="color-ball" style={style}>
</div>
)
}
}
export default ColorBall;
index.css:
html, body {
background-color: #333;
}
.color-ball {
border-radius: 50%;
border-style: solid;
}
.color-ball:after {
content: '';
display: block;
padding-top: 100%;
}
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import CreateBall from './conponents/ColorBall';
ReactDOM.render(
<ColorBall />,
document.getElementById('root')
);
绘制效果图:
实现小球的运动效果
以下列举主要的组件:
ColorBall.js:
import React, { PropTypes } from 'react';
class ColorBall extends React.Component {
render () {
const {point, color, size} = this.props;
const {x, y} = point;
const style = {
width: size + 'px',
borderColor: color,
borderWidth: '10px',
transform: `translate(${x}px, ${y}px)`
};
return (
<div className="color-ball" style={style}></div>
);
}
}
ColorBall.propTypes = {
point: PropTypes.object.isRequired,
color: PropTypes.string,
size: PropTypes.number
};
ColorBall.defaultProps = {
color: '#0094ff',
size: 100
};
export default ColorBall;
App.js:
import React, { Component } from 'react';
import { findDOMNode } from 'react-dom';
import ColorBall from './components/ColorBall';
import './App.css';
import { createBall } from './utils';
class App extends Component {
constructor () {
super();
this.state = createBall();
}
/*
* 检测球是否需要转向
* 如果球撞墙了,根据碰撞的墙面(上、下、左、右)对球的direction属性进行修改
* 最终返回一个新的球对象
*/
checkIfNeedChangeDirection (ball) {
if (!this.container) {
return;
}
// 获取小球父节点的宽度和高度
const {offsetWidth, offsetHeight} = this.container;
const {point, size, direction, ...other} = ball;
const newDirection = {...direction};
if (point.x < 0 || point.x + size > offsetWidth) {
// 撞到了左侧或右侧的墙,改变direction中的x为其负数
newDirection.x *= -1;
}
if (point.y < 0 || point.y + size > offsetHeight) {
// 撞到了上侧或下侧的墙,改变direction中的y为其负数
newDirection.y *= -1;
}
return {
point,
size,
...other,
direction: newDirection
};
}
/*
* 移动小球方法,参数为一个小球对象
* 返回移动后的小球
*/
moveBall (ball) {
let newBall = this.checkIfNeedChangeDirection(ball);
// 根据小球的原始位置和方向以及速度,计算出新的小球位置
newBall.point.x += newBall.direction.x * newBall.speed;
newBall.point.y += newBall.direction.y * newBall.speed;
return newBall;
}
/*
* 移动小球,并将新的小球设置到state里
*/
updateBall () {
const ball = this.state;
const newBall = this.moveBall(ball);
this.setState(newBall);
// 使用requestAnimationFrame方法,实现每秒调用60次updateBall方法
// 具体介绍请谷歌
window.requestAnimationFrame(() => this.updateBall());
}
componentDidMount () {
// 获取小球父节点的Element对象
// 在检测小球碰撞的时候会用到
this.container = findDOMNode(this.refs.container);
// 开始移动小球
this.updateBall();
}
render () {
const {point, color, size} = this.state;
return (
<div className="app" ref="container">
<ColorBall point={point} size={size} color={color}/>
</div>
);
}
}
export default App;
在App.css中,关于padding-top的值为百分比的使用问题,不了解的可以参考:CSS自适应占位。
App.css:
body, html, .app {
background-color: #333;
height: 100vh;
width: 100vw;
overflow: hidden;
}
.color-ball {
position: absolute;
left: 0;
top: 0;
border-style: solid;
border-radius: 50%;
transition: all ease-out .3s;
}
.color-ball:after {
content: '';
display: block;
padding-top: 100%;
}
utils.js:
const colors = [
'#F44336',
'#FFCDD2',
'#E91E63',
'#F06292',
'#D81B60',
'#AD1457',
'#9C27B0',
'#CE93D8',
'#7B1FA2',
'#673AB7',
'#B39DDB',
'#7E57C2',
'#3F51B5',
'#9FA8DA',
'#5C6BC0',
'#2196F3',
'#90CAF9',
'#64B5F6',
'#00BCD4',
'#80DEEA',
'#009688',
'#B2DFDB',
'#4CAF50',
'#A5D6A7',
'#8BC34A',
'#C5E1A5',
'#CDDC39',
'#E6EE9C',
'#FFEB3B',
'#FFF176',
'#FFC107',
'#FFD54F',
'#FF9800',
'#FFCC80',
'#795548',
'#9E9E9E',
'#607D8B'
];
export function createBall () {
return {
point: {x: 0, y: 0},
direction: {x: Math.random(), y: Math.random()},
color: colors[Math.floor(Math.random() * (colors.length - 1))],
size: 50 + Math.random() * 100,
speed: 5 + Math.random() * 10
};
}
运动时的小球某一时刻截图:
全文完。