如何在反应中取消和重置css动画?

时间:2016-08-30 03:49:33

标签: javascript css animation reactjs

我想做什么

我有一张精灵表,我正在使用它来制作一些简单的动画。我有一个有两个动画的“玩家”。一个用于攻击,一个用于站立。当前行为如下:“stand”是默认动画。单击播放器时,播放“攻击”动画并切换回“站立”。

对于在攻击时点击播放器的特殊情况,我希望动画“攻击”动画重置。

我的代码

// React Component
class Player extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      timeout: null
    };
  }

  attack(e) {
    if (this.state.timeout) { clearTimeout(this.state.timeout); } 
    var $el = $(e.target);
    $el.css({
      backgroundPosition: '0 220px',
      animationName: 'attack',
      width: '300px'
    });
    this.state.timeout = setTimeout(function() {
      $el.css({
        backgroundPosition: 'left top',
        animationName: 'stand',
        width: '250px'
      });
    }, 2000);
  }

  render () {
    return (
      <div onClick={this.attack.bind(this)} className="player main">{this.props.name}</div>
    );
  }
}


     /* The css */
     .player {
        width: 250px;
        height: 220px;
        background: url('assets/player.png') left top;
        animation: stand 1.2s steps(3) infinite;
        animation-direction: alternate;
      }
      @keyframes stand {
        100% { 
          background-position: -750px 0; 
        }
      }
      @keyframes attack {
        100% { 
          background-position: -900px 220px; 
        }
      }

我尝试做什么

我知道,因为我将setTimeout设置为“stand”动画,我将不得不取消它并创建一个新的setTimeout来追踪“stand”动画。但是,它看起来仍然有点时髦。我尝试使用forceUpdate()来查看是否可以重新渲染并重置所有内容然后启动“攻击”动画,但它似乎没有做任何事情。

我有另一个想法,使用jquery删除并重新附加dom元素,但我觉得它会变得混乱,我相信我可能会以错误的方式处理这个问题。你们有什么想法吗?

2 个答案:

答案 0 :(得分:1)

对于复杂的动画,您可以使用可以从https://github.com/chenglou/react-motionhttps://egghead.io/playlists/react-react-animation-using-react-motion

学习的https://egghead.io/lessons/react-react-motion-introduction-to-the-spring-component

对于简单的,我宁愿在元素中添加和删除类以启用动画并重置它。

如果我正确理解它,你正在使用jQuery内部反应。那么更新CSS,你不应该在反应中使用它。

应该有更强有力的理由在反应中使用jQuery,因为更新内联css非常简单。

以下是我尝试这样做的方式:

&#13;
&#13;
// React Component
class Player extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        direction: null,
        timeout: null
      };
    }

    attack(e) {

      //following line can be used to identify multiple targets
      //let target = (e.target);
      if (this.state.timeout !== null) {
        window.clearTimeout(this.state.timeout)
      }
      let timeout = setTimeout(() => {
        this.setState({
          direction: null,
          timeout: null
        });
      }, 8000)
      let direction = null;
      if (e.ctrlKey) {
        direction = 'anticlockwise'
      } else {
        direction = 'clockwise'
      }
      if (this.state.direction !== direction) {
        this.setState({
          direction, timeout
        });
      }

    }

    render() {
        let classNames = ["player", "main"];
        let styles = {}
        if (this.state.direction !== null) {
          if (this.state.direction === 'clockwise')
            styles.zoom = 0.8
          else
            styles.zoom = 1.2
          classNames.push(this.state.direction)
        }
        return ( < div onClick = {
            this.attack.bind(this)
          }
          style={styles}
          className = {
            classNames.join(' ')
          } > {
            this.props.name
          } < /div>
    );
  }
}
ReactDOM.render(<Player / > , document.getElementById('game'));
&#13;
.player {
  width: 100px;
  height: 100px;
  margin: 50px;
  zoom: 1;
  transition: all linear 0.3s;
  display: inline-block;
  background-color: #ccc;
  animation-timing-function: linear;
}
.clockwise {
  animation: clockwise 5s infinite;
}
.anticlockwise {
  animation: anticlockwise 5s infinite;
}
@keyframes clockwise {
  0% {
    transform: rotate(0deg)
  }
  50% {
    transform: rotate(180deg)
  }
  100% {
    transform: rotate(360deg)
  }
}
@keyframes anticlockwise {
  0% {
    transform: rotate(360deg)
  }
  50% {
    transform: rotate(180deg)
  }
  100% {
    transform: rotate(0deg)
  }
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="game"></div>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

我们可以简化这一点(为了清楚起见仍然有点冗长)。制作了一个模块,可以让您在名为Style It的组件中编写明文CSS,实例可以利用它。

npm install style-it --save

攻击模式OPEN ON JSFIDDLE

import React from 'react';
import Style from 'style-it';

class Intro extends React.Component {
    constructor(props) {
    super(props);

    this.state = {
        mode: "stand"
    }
    this.handleClick = this.handleClick.bind(this);
  }
  render() {
    return Style.it(`
      #thing {
        margin: 50px;
        width: 50px;
        height: 50px;
        background-color: green;
      }
      .attack {
        -webkit-animation: attack 500ms infinite;
        -moz-animation: attack 500ms infinite;
        animation: attack 500ms infinite;
      }
      @-webkit-keyframes attack {
        0% { background-color: green; transform: scale(1);}
        100% { background-color: red;  transform: scale(2);}
      }
      @-moz-keyframes attack {
        0% { background-color: green; transform: scale(1);}
        100% { background-color: red;  transform: scale(2);}
      }
            @keyframes attack {
        0% { background-color: green; transform: scale(1);}
        100% { background-color: red;  transform: scale(2);}
      }
    `,
        <div>
        <button onClick={this.handleClick}> Click to toggle mode: [{this.state.mode}] </button>
        <div id="thing" className={this.state.mode} />
        </div>
    );
  }

  handleClick(e) {
    if (this.state.mode === "stand") {
        this.setState({mode: "attack"});
    } else {
        this.setState({mode: "stand"});
    }
  }
}

ReactDOM.render(
  <Intro />,
  document.getElementById('container')
);