使用React.js实现slideUp()和slideDown()动画

37

我创建了一个 React 组件,其中包含 slideUp() 和 slideDown() 动画。我使用 jQuery 的 slideup 和 slidedown 方法进行了实现。

我需要使用 React 动画来实现这个功能。

我阅读了关于 ReactTransitionGroupReactCSSTransitionGroup 的资料。通过所学的解释方式,我们可以在 DomNode 被挂载到组件或卸载后做到这个功能(如果我错了,请纠正我)。

我的问题是 --> 如何使用 React 方式来执行 slideUp() 和 slideDown(),而且不使用 jQuery。

请查看此 jsFiddle:https://jsfiddle.net/guc3yrm1/

P.S-> 请解释为什么与 jQuery 相比,这个 React 动画部分似乎有点困难(我是一个 jQuery 爱好者)。

var Hello = React.createClass({
    getInitialState: function() {
        return {
            slide: false,
        }
    },
    slide: function() {
        if (this.state.slide) {
            $(this.refs.slide).slideDown();
            this.setState({
                slide: false
            });
        } else {
            $(this.refs.slide).slideUp();
            this.setState({
                slide: true
            });
        }
    },
    render: function() {
        return ( 
            <div>
                <input type = "button" value = "clickme" onClick = {this.slide}/> 
                <br />
                <br />
                <div className = "slide" ref="slide" >< /div>
            </div>
        );
    }
});

ReactDOM.render( < Hello name = "World" / > ,
    document.getElementById('container')
);

1
只是好奇:为什么你不想在这里使用jQuery? - Chris
1
https://dev59.com/MIzda4cB1Zd3GeqPsucI - Arun AK
@Chris,我可以借助jQuery完成这个任务。但我很好奇如何在React组件中使用reactTransitionAPI处理静态内容。最终,我们可以通过React的方式避免不必要的重新渲染。 - Vimal Ramakrishnan
3个回答

49

您可以在这两个动画API中实现动画效果。这是它们之间的主要区别:

ReactTransitionGroup是构建ReactCSSTransitionGroup的API。两者之间的主要区别在于,ReactTransitionGroup动画是用JavaScript编写的,而不是CSS,并提供回调函数在动画完成时调用,而不是依赖于CSS转换事件。

我的结论是,对于简单任务,请使用CSS动画,对于复杂任务,请使用JavaScript。

例如,如果组件具有静态高度,则可以通过CSS实现它,如下面的示例所示。但是,如果宽度/高度是动态的,则可以使用JavaScript进行操作。在JavaScript示例中,我使用Velocity库来执行动画。它比jQuery的动画性能更好。当然,您可以自己实现动画,但为什么要重新发明轮子呢?

我已经使用这两个API实现了slideUp/slideDown。请查看下面的示例。

(CSS) 通过ReactCSSTransitionGroup实现:

const CSSTransitionGroup = React.addons.CSSTransitionGroup;
const TransitionGroup = React.addons.TransitionGroup;

class Example extends React.Component{
    constructor(props) {
        super(props);
        this.state = { visible: false };
        this.handleClick = this.handleClick.bind(this)
    }

    handleClick() {
     this.setState({ visible: ! this.state.visible });
    }

    render() {
        return <div>
            <button onClick={this.handleClick}>{this.state.visible ? 'Slide up' : 'Slide down'}</button>
            <CSSTransitionGroup transitionName="example">
             { this.state.visible ? <div className='panel' /> : null }
            </CSSTransitionGroup>
        </div>
    }
}

React.render(<Example />, document.getElementById('container'));
.panel {
    width: 200px;
    height: 100px;
    background: green;
    margin-top: 10px;
}

.example-enter {
    height: 0px;
}

.example-enter.example-enter-active {
    height: 100px;
    -webkit-transition: height .3s ease;
}

.example-leave.example-leave-active {
    height: 0px;
    -webkit-transition: height .3s ease;
}
<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>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.1/react-with-addons.js"></script>
<div id="container">
    <!-- This element's contents will be replaced with your component. -->
</div>

JSFiddle - React Slide up and Slide down animation - CSS Transtion Group


(Javascript) Implementation via ReactTransitionGroup:

const TransitionGroup = React.addons.TransitionGroup;

class Example extends React.Component{
    constructor(props) {
        super(props);
        this.state = { visible: false };
        this.handleClick = this.handleClick.bind(this)
    }

    handleClick() {
        this.setState({ visible: ! this.state.visible });
    }

    render() {
        return <div>
            <button onClick={this.handleClick}>{this.state.visible ? 'Slide up' : 'Slide down'}</button>
                <TransitionGroup>
                    { this.state.visible ? <Accordion /> : null }
                </TransitionGroup>
            </div>
        }
    }

    class Accordion extends React.Component {
        componentWillEnter (callback) {
            const element = this.container.getDOMNode();
            Velocity(element, 'slideDown', { duration: 300 }).then(callback);
        }

        componentWillLeave (callback) {
            const element = this.container.getDOMNode();
            Velocity(element, 'slideUp', { duration: 300 }).then(callback);
        }

        setContainer(c) {
            this.container = c;
        }

        render() {
            return <div className="panel" ref={this.setContainer.bind(this)}>
                Lorem Ipsum is simply dummy text of the printing and typesetting industry.
                Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
            </div>
        }
    }

React.render(<Example />, document.getElementById('container'));
.panel {
    background: green;
    margin-top: 10px;
}
<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>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.1/react-with-addons.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.4.3/velocity.min.js"></script>

<div id="container">
    <!-- This element's contents will be replaced with your component. -->
</div>

JSFiddle - React Slide up和Slide down动画 - Javascript Transition组


Credits:


8
如果面板没有固定的高度怎么办? - Vic
1
.invisble {max-height: 0%; overflow: hidden;} .visible{ max-height: 100%; } 隐藏 {最大高度:0%; 溢出:隐藏;} 可见 {最大高度:100%;} - noa-dev
1
嘿,在这种情况下,我们可以通过Javascript - ReactTransitionGroup来实现它。我已经更新了我的答案,并添加了使用Velocity的Javascript示例。 - Jordan Enev
@noa-dev,你能否帮我fork一下我的JSFiddle,并通过CSS进行修改吗?https://jsfiddle.net/jordan_enev/xtbxk20g/ - Jordan Enev
@JordanEnev 我进行了分支并在我的回复中提到了你 :) - noa-dev
@JordanEnev 我发现只有在添加组件属性时才能正常工作,例如 <CSSTransitionGroup component="div"... - Phil Andrews

12
如果您(像我一样)正在寻找React替代jQuery的slideDown/slideUp,那么react-slidedown似乎是一个易于使用的React组件。它的Github页面上有一个演示示例代码

4

根据Jordan Enev的要求,我fork了他的JSFiddle。

这里提供了一种不需要React Css Transition Group的解决方案。我个人喜欢使用class-toggles。这样你可以按照自己的喜好创建css动画。

https://jsfiddle.net/fyuh32je/3/

(完整代码请查看链接)

class Example extends React.Component{
    constructor(props) {
        super(props);
        this.state = { visible: 'panel' };
        this.handleClick = this.handleClick.bind(this)
    }

    handleClick() {
        this.setState({ visible: this.state.visible == 'panel'? 'panel visible' : 'panel' });
    }

    render() {
        return <div>
            <button onClick={this.handleClick}>{!this.state.visible == 'panel' ? 'Slide up' : 'Slide down'}</button>
                <div className={this.state.visible}>
                <p>This is some dynamic content!</p>
                <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p>
              </div>
        </div>
    }
}

React.render(<Example />, document.getElementById('container'));

我知道像这样使用可见状态变量很不好,但我在工作中没有太多时间去做太多更改。请注意,我们使用可见类来切换带有动画效果的div容器。
一般来说,可以通过css中max-height属性的hacky用法来动画化动态高度容器。

1
嘿,感谢你的努力!实际上,你正在硬编码面板的高度值,一旦它可见。想法是使一切都是动态的,即面板的高度与面板内容的高度相关。请查看我的Javascript示例。此外,使用ReactCSSTransitionGroup,您可以跳过手动设置CSS类的名称。 - Jordan Enev
抱歉,我忘记删除固定高度声明了。我更新了我的JS Fiddle。您可以清楚地看到容器根据其内容动态地行为,并在打开时进行动画处理,而没有固定的高度。您可以测试并添加或删除一些文本行。 - noa-dev
感谢您提供的解决方法!正如您已经提到的,这是一个有点hackish的解决方式。此外,您还需要手动处理CSS类名。当然,我更喜欢使用React进行动画处理的方式!感谢您的贡献! - Jordan Enev
@noa-dev,我该如何改变你在下面链接中的逻辑,同时保留我的现有点击事件功能?我在React方面还是初学者。请参见:https://dev59.com/uqjka4cB1Zd3GeqPF-cW - Jonca33

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接