react过渡动画效果的实现,react-transition-group

本文介绍react相关的过渡动画效果的实现

有点类似vue的transition组件,主要用于组件mount和unmount之前切换时应用动画效果

  1. 安装

    cnpm install react-transition-group --save
    
  2. transition动画

    import React from 'react'
    import ReactDOM from 'react-dom'
    import Transition from 'react-transition-group/Transition';
    const duration = 300;
    const defaultStyle = {
        transition: `opacity ${duration}ms ease-in-out`,
        opacity: 0,
        width: "100px",
        height: "100px",
        background: "red"
    }
    const transitionStyles = {
        entering: { opacity: 0 },
        entered:  { opacity: 1 },
    };
    class MyComponent extends React.Component {
        constructor() {
            super();
                this.state = {
                in: false
            }
        }
        toggleEnterState = () => {
            this.setState({in: !this.state.in})
        }
        render() {
            return (
            <div>
                <Transition in={this.state.in} timeout={1000} mountOnEnter={true} unmountOnExit={true}>
                    {(state) => (
                        <div style={{
                        ...defaultStyle,
                        ...transitionStyles[state]
                        }}>
                        I'm A fade Transition!
                        </div>
                    )}
                </Transition>
                <button onClick={this.toggleEnterState}>Click to Enter</button>
            </div>
            )
        }
    }
    ReactDOM.render(
        <MyComponent/>,
        document.getElementById('root')
    ) 
    
  3. transition动画配套api

    ** children 
        指的是Transition标签包含的待应用动画的元素,可以使用react的元素,也可以直接用函数,函数可以接受state参数
        state的代表动画的4个状态
            entering
            entered
            exiting
            exited
    ** in
        应用于Transition标签上面,切换enter和exit,从而出现动画效果,布尔值
    ** mountOnEnter
        在元素enter的时候才挂载,布尔值
    ** unmountOnExit
        在元素exit的时候销毁,布尔值
    ** appear
        默认情况下Transition初次挂载的时候不应用动画
        设置为apear之后,会自动应用一次enter动画
        布尔值
    ** enter
        是否启用enter时候的动画,布尔值
        作用和设置timeout为0一样
    ** exit
        是否启用exit时候的动画,布尔值
        作用和设置timeout为0一样
    ** timeout
        过渡的持续时间,必须设置此值,除非addEventListener提供了
        timeout = {500}或者
        timeout = {{
            enter: 300,
            exit: 500
        }}
    ** addEndListener
        用来监听dom节点的transition结束事件
        addEndListener = {
            (node,done) => {
                node.addEventListener('transitionend', function(){
                    alert(111);
                });
                done();
            }
        }
        node是dom元素节点,done是切换状态的回调函数
    ** onEnter
        用来监听 enter 状态的钩子函数
        onEnter={ 
            (node,isAppearing) => {console.log(node,isAppearing)
        }
        node是dom节点
        isAppearing是appear属性值
        另外 onEntering 和 onEntered用法类似
    ** onExit   
        用来监听 exit 状态开始触发的钩子函数
        onExit={ 
            (node) => {console.log(node)
        }
        另外 onExiting 和 onExited 用法类似
    
  4. animate动画

    ** index.js
        import React from 'react'
        import ReactDOM from 'react-dom'
        import { CSSTransition } from 'react-transition-group';
        import './index.css';
        const defaultStyle = {
            width: "100px",
            height: "100px",
            background: "red"
        }
        class MyComponent extends React.Component {
            constructor() {
                super();
                this.state = {
                    in: true
                }
            }
            toggleEnterState = () => {
                this.setState({in: !this.state.in})
            }
            render() {
                return (
                    <div>
                        <CSSTransition in={this.state.in} timeout={500} classNames='bounceInLeft'>
                            {(state) => (
                                <div style={{
                                ...defaultStyle
                                }}>
                                I'm A fade Transition!
                                </div>
                            )}
                        </CSSTransition>
                        <button onClick={this.toggleEnterState}>Click to Enter</button>
                    </div>
                )
            }
        }
        ReactDOM.render(
            <MyComponent/>,
            document.getElementById('root')
        )
    ** index.css
        @keyframes bounceInLeft {
            from, 60%, 75%, 90%, to {
                animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
            }
            0% {
                opacity: 0;
                transform: translate3d(-3000px, 0, 0);
            }
            60% {
                opacity: 1;
                transform: translate3d(25px, 0, 0);
            }
            75% {
                transform: translate3d(-10px, 0, 0);
            }
            90% {
                transform: translate3d(5px, 0, 0);
            }
            to {
                transform: none;
            }
        }
        @keyframes bounceOutRight {
            20% {
                opacity: 1;
                transform: translate3d(-20px, 0, 0);
            }
            to {
                opacity: 0;
                transform: translate3d(2000px, 0, 0);
            }
        }
        .bounceInLeft-enter{
            animation: bounceInLeft 1s 1;
        }
        .bounceInLeft-exit{
            animation: bounceOutRight 1s 1;
        }
    
  5. animate动画配套api

    ** classNames 
        用在CSSTransition标签上面,自动添加状态后缀名
        classNames = "demo";
        会依次应用 demo-enter,demo-enter-active,demo-exit,demo-exit-active,demo-appear,demo-appear-active
        如果单独制定class的name的话可以使用如下
        classNames = {{
            appear: 'demo1',
            appearActive: 'demo2',
            enter: 'demo3',
            enterActive: 'demo4',
            exit: 'demo5',
            exitActive: 'demo6'
        }}
    ** onEnter
        在enter或者appear类应用完成后立马调用回调函数
            onEnter={ 
                (node,isAppearing) => {console.log(node,isAppearing)}
            }
    ** onEntering
        在enter-active或者appear-active应用完成后立马调用回调函数
            onEntering={ 
                (node,isAppearing) => {console.log(node,isAppearing)}
            }
    ** onEntered
        在enter或者appear移除完成后立马调用回调函数
            onEntered={ 
                (node,isAppearing) => {console.log(node,isAppearing)}
            }
    ** onExit
        在exit类应用完成后立即调用回调函数
            onEntered={ 
                (node) => {console.log(node)}
            }
    ** onExiting
        在exit-active类应用完成后立即调用回调函数
            onExiting={ 
                (node) => {console.log(node)}
            }
    ** onExited
        在exit类移除后立即调用
            onExited={ 
                (node) => {console.log(node)}
            }
    
  6. TransitionGroup

    专门处理列表动画而诞生的组件,只要在TransitionGroup中的元素减少或者增加,自动为Transition或者CSSTransition应用in属性
    import React from 'react'
    import ReactDOM from 'react-dom'
    import Transition from 'react-transition-group/Transition';
    import {TransitionGroup} from 'react-transition-group'
    const duration = 300;
    const defaultStyle = {
        transition: `opacity ${duration}ms ease-in-out`,
        opacity: 0,
        width: "100px",
        height: "100px",
        background: "red"
    }
    const transitionStyles = {
        entering: { opacity: 0 },
        entered:  { opacity: 1 },
    };
    class MyComponent extends React.Component {
        constructor() {
            super();
            this.state = {
                arr: ['a','c','d','e']
            }
        }
        addItem = () => {
        this.setState({
            arr: this.state.arr.concat(['f'])
        });
        }
        render() {
            return (
            <div>
                <TransitionGroup component="span" appear>
                    {this.state.arr.map( (item,index) => (
                        <Transition key={index} timeout={0}>
                            {(state) => (
                                <div style={{
                                ...defaultStyle,
                                ...transitionStyles[state]
                                }}>
                                {item}
                                </div>
                            )}
                        </Transition>
                    ) )}
                </TransitionGroup>
                <button onClick={this.addItem}>添加元素</button>
            </div>
            )
        }
    }
    ReactDOM.render(
        <MyComponent/>,
        document.getElementById('root')
    )
    
  7. TransitionGroup配套api

    ** component
        默认TransitionGroup是渲染成div,可以通过指定component改变这一默认行为
    ** appear
        是否执行初次渲染enter动画
    ** enter
        是否开启enter动画
    ** exit
        是否开启exit动画
    ** childFactory
        此函数是TransitionGroup将要展示子元素的拦截器
        childFactory={(el) => {console.log(el);return el}}