Javascript 在组件的不同状态之间平滑过渡

Javascript 在组件的不同状态之间平滑过渡,javascript,css,reactjs,css-transitions,Javascript,Css,Reactjs,Css Transitions,我有一个简单的组件,如下所示: .your-component-name{ // inactive css styling here } .your-component-name.active { // active css styling here } var component=React.createClass({ render:function(){ 如果(此.props.isCollapsed){ 返回此.renderCollapsed(); } 返回这个。renderAc

我有一个简单的组件,如下所示:

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

.your-component-name.active {
  // active css styling here
}
var component=React.createClass({
render:function(){
如果(此.props.isCollapsed){
返回此.renderCollapsed();
}
返回这个。renderActive()
},
renderActive:function(){
返回(
...
);
},
renderCollapsed:function(){
返回(
...
);
},
});
基本上,当属性更改时,组件将显示活动状态或折叠状态

我想的是,当属性发生更改时,即active->collapse,或相反,我希望旧视图“收缩”或“展开”平滑地显示新视图。例如,如果它是活动的->折叠,我希望活动的UI缩小到折叠UI的大小,并平滑地显示它

我不知道如何达到这个效果。请分享一些想法。谢谢

而不是有条件地呈现 组件,您可以在同一服务器上切换类 组成部分。可以按如下方式创建活动类和折叠类:

例如:

.active{
-webkit转换:-webkit转换.5s线性;//的转换
//0.5秒
高度:200px;
}
.崩溃{
高度:0px;
}

查看示例

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

css应该如下所示:

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

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

当您要为活动和折叠的每个组件渲染两个不同的组件时,请将它们包装在一个div中,该div通过CSS控制高度

render:function(){
var cls=this.props.isCollapsed()?“collapsed”:“expanded”;
返回(
{
this.props.isCollapsed()?
此.renderCollapsed():
这个
}
);
}
在CSS中:

.wrapper{
过渡:变换。5s线性;
}
.扩大{
高度:200px;
}
.崩溃{
高度:20px;
}

以下是一个简单的工作示例:

常量可折叠=({active,toggle})=>
切换
文本
const component=React.createClass({
getInitialState(){
返回{active:false}
},
切换(){
this.setState({active:!this.state.active})
},
render(){
返回可折叠({active:this.state.active,toggle:this.toggle})
}
})
ReactDOM.render(React.createElement(组件)、document.querySelector('#root'))
。可折叠{
高度:1.5雷姆;
过渡段:高度0.25s线性;
背景:#333;
边界半径:0.25雷姆
}
.可折叠的{
身高:7雷姆
}

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

下面是一个工作示例

下面是代码示例:

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'));
const runTransition=(节点,{property='opacity',from,to,duration=600,post=''},end)=>{
const dif=到-从;
const start=Date.now();
常量动画=()=>{
const step=Date.now()-开始;
如果(步骤>=持续时间){
node.style[property]=to+post;
返回typeof end=='function'&&end();
}
const val=from+(dif*(步长/持续时间));
node.style[property]=val+post;
请求动画帧(动画);
}
请求动画帧(动画);
}
类Comp.Component{
建造师(道具){
超级(道具);
此.state={
isCollapsed:错误
}
this.onclick=(e)=>{
this.hide(例如currentTarget,()=>{
this.setState({isCollapsed:!this.state.isCollapsed})
});
};
this.refF=(n)=>{
n&&this.show(n);
};
}
render(){
if(this.state.isCollapsed){
返回此.renderCollapsed();
}
返回这个。renderActive()
}
renderCollapsed(){
返回(
我崩溃了
)
}
渲染的{
返回(
我很活跃
)
}
显示(节点,cb){
runTransition(节点,{from:0,to:1},cb);
}
隐藏(节点,cb){
runTransition(节点,{from:1,to:0},cb);
}
}
ReactDOM.render(,document.getElementById('content'));
当然,对于这种方法,您唯一的机会是依赖于状态,而不是组件的道具,如果您必须处理它们,您可以始终在componentWillReceiveProps方法中设置这些道具

更新
更新了更清晰的示例,显示了此方法的好处。转换更改为javascript动画,不依赖于transitionend事件

标准方法是使用CSSTransitionGroup from,这非常简单。使用
CSSTransitionGroup
包装组件,并在enter和leave上设置超时,如下所示:

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

{items}
从:

“在此组件中,将新项添加到CSSTransitionGroup时 将获得示例enter CSS类和示例enter active CSS 在下一个勾号中添加了类。“

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

里面也有很好的解释,看看吧


还有用于动画的第三方组件。

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

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,
};
import React,{Component}来自'React';
从“velocity react”导入{VelocityTransitionGroup};
导出默认类ToggleContainer扩展组件{
构造函数(){
超级();
this.renderContent=this.renderContent.bind(this);
}
renderContent(){
如果(这个.道具.表演){
返回(
{th