在组件中的不同状态之间进行平滑过渡

时间:2016-12-08 02:50:28

标签: javascript css reactjs css-transitions

我有一个像这样的简单组件:

var component = React.createClass({
  render: function(){
      if (this.props.isCollapsed){
         return this.renderCollapsed();
      }
      return this.renderActive()
  },
  renderActive: function(){
    return (
      <div>
      ...
      </div>
    );
  },
  renderCollapsed: function(){
    return (
      <div>
      ...
      </div>
    );
  },
});

基本上,当属性更改时,组件将显示活动状态或折叠状态。

我在想的是,当房产改变发生时,即活动 - >崩溃,或者反过来,我想要旧视图&#34;收缩&#34;或&#34;扩展&#34;顺利展示新观点。例如,如果它是活动的 - >崩溃,我希望活动用户界面缩小到折叠用户界面的大小,并顺利显示。

我不确定如何达到这个效果。请分享一些想法。谢谢!

7 个答案:

答案 0 :(得分:5)

  

而不是有条件地渲染a的两个不同的结束状态   组件,您可以改为切换类   零件。您可以使用以下活动和折叠类:

例如:

.active{
  -webkit-transition: -webkit-transform .5s linear;  // transition of 
                                                     // 0.5 of a second
  height: 200px;
}

.collapsed{
  height: 0px;
}

查看this resource示例

答案 1 :(得分:3)

这是一个最小的工作示例:

const collapsible = ({active, toggle}) =>
<div>
  <button type="button" onClick={toggle}>Toggle</button>
  <div className={'collapsible' + (active? ' active': '')}>
    text
  </div>
</div>


const component = React.createClass({
  getInitialState() {
    return {active: false}
  },
  toggle() {
    this.setState({active: !this.state.active})
  },
  render() {
    return collapsible({active: this.state.active, toggle: this.toggle})
  }
})
ReactDOM.render(React.createElement(component), document.querySelector('#root'))
.collapsible {
  height: 1.5rem;
  transition: height 0.25s linear;
  background: #333;
  border-radius: 0.25rem
}
.collapsible.active {
  height: 7rem
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<div id="root"></div>

视图可以通过CSS transition平滑地“缩小”或“展开”,这是通过更改CSS属性触发的。

要使用React控制CSS属性,我们可以将状态更改反映到className中的属性值或render()

在此示例中,.active类会影响height值,并由state.active控制。响应状态更改,React切换该类,并触发CSS转换。

要获得更平滑的过渡,请参阅this article

答案 2 :(得分:3)

标准方法是使用react-transition-group中的CSSTransitionGroup,这非常简单。使用CSSTransitionGroup包裹组件并在进入和离开时设置超时,如下所示:

<CSSTransitionGroup
      transitionName="example"
      transitionEnterTimeout={500}
      transitionLeaveTimeout={300}>
      {items}
</CSSTransitionGroup>

来自v1-stable docs

  

“在此组件中,当一个新项目添加到CSSTransitionGroup时   将得到示例 - 输入CSS类和示例 - 输入 - 活动CSS   在下一个刻度中添加了类。“

为CSS类添加样式以获取正确的动画。

React docs中也有很好的解释,请查看。

动画也有第三方组件。

答案 3 :(得分:2)

这种情况的另一种方法可能是在动画完成后改变状态。它的好处是你不仅可以应用转换,而且可以应用你想要的任何动作(js动画,smil等等),主要的是不要忘记调用结束回调;)

以下是工作示例CodePen

以下是代码示例:

const runTransition = (node, {property = 'opacity', from, to, duration = 600, post = ''}, end) => {
  const dif = to - from;
  const start = Date.now();

  const animate = ()=>{
    const step = Date.now() - start;
    if (step >= duration) {
      node.style[property] = to + post;
      return typeof end == 'function' && end();
    }

    const val =from + (dif * (step/duration));
    node.style[property] =  val + post;
    requestAnimationFrame(animate);
  }

  requestAnimationFrame(animate);

}

class Comp extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isCollapsed: false
    }

    this.onclick = (e)=>{
       this.hide(e.currentTarget,()=>{
         this.setState({isCollapsed: !this.state.isCollapsed})
       });
     };

    this.refF = (n)=>{
       n && this.show(n);
     };
  }

  render() {
    if (this.state.isCollapsed){
         return this.renderCollapsed();
      }
      return this.renderActive()
  }

  renderCollapsed() {
    return (
      <div 
        key='b'
        style={{opacity: 0}}
        ref={this.refF}
        className={`b`}
        onClick={this.onclick}>
          <h2>I'm Collapsed</h2>
      </div>
      )
  }

  renderActive() {
    return (
      <div 
        key='a'
        style={{opacity: 0}}
        ref={this.refF}
        className={`a`}
        onClick={this.onclick}>
          <h2>I'm Active</h2>
      </div>
      )
  }

  show(node, cb)  {
    runTransition(node, {from: 0, to: 1}, cb);
  }

  hide(node, cb) {
    runTransition(node, {from: 1, to: 0}, cb);
  }

}

ReactDOM.render(<Comp />, document.getElementById('content'));

可以肯定的是,对于这种工作方法,你唯一的机会是继续使用状态,而不是Component的道具,如果你必须处理它们,你可以随时在componentWillReceiveProps方法中设置它。

更新

Codepen link更新了更明确的示例,该示例显示了此方法的好处。转换更改为javascript动画,而不依赖于transitionend事件。

答案 4 :(得分:1)

您可以添加描述活动状态的类,即。 .active并在切换状态时切换该类。

css看起来应该是这样的:

.your-component-name{
  // inactive css styling here
}

.your-component-name.active {
  // active css styling here
}

答案 5 :(得分:1)

如果你想为每个活动和折叠渲染两个不同的组件,请在CSS的帮助下将它们包装在一个控制高度的div中。

render: function(){
var cls = this.props.isCollapsed() ? 'collapsed' : 'expanded';
return(
  <div className={cls + ' wrapper'}>
    {
      this.props.isCollapsed() ?
       this.renderCollapsed() :
       this.renderActive()
    }
  </div>
);
}

并在你的CSS中:

.wrapper{
  transition: transform .5s linear;
}

.expanded{  
  height: 200px;
}

.collapsed{
  height: 20px;
}

答案 6 :(得分:0)

这里有一个使用Velocity-React库的Toggle react组件,非常适合为React uis中的过渡提供动画:

import React, { Component } from 'react';
import { VelocityTransitionGroup } from 'velocity-react';

export default class ToggleContainer extends Component {
    constructor () {
        super();

        this.renderContent = this.renderContent.bind(this);
    }

    renderContent () {
        if (this.props.show) {
            return (
                <div className="toggle-container-container">
                    {this.props.children}
                </div>
            );
        }
        return null
    }

    render () {
        return (
            <div>
                <h2 className="toggle-container-title" onClick={this.props.toggle}>{this.props.title}</h2>
                <VelocityTransitionGroup component="div" enter="slideDown" leave="slideUp">
                    {this.renderContent()}
                </VelocityTransitionGroup>
            </div>
        );
    }

};

ToggleContainer.propTypes = {
    show: React.PropTypes.bool,
    title: React.PropTypes.string.isRequired,
    toggle: React.PropTypes.func.isRequired,
};

希望它有所帮助!