Make interesting things with react!

5 篇文章 0 订阅

本文原创地址链接: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
  };
}

运动时的小球某一时刻截图:
这里写图片描述
全文完。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值