乐趣区

reacttransitiongroup动画库Transition组件使用

react-transition-group 动画库

这个库包括 3 个组件:Transition,CSSTransition,TransitonGroup,今天做项目刚好用到了 Transition 组件,记录一下使用过程中的总结,另外两个组件用到了再做介绍。或者移步到 react 官网动画库(react-transition-group)的新写法

CSS3 的 transition 属性

该属性可以对元素里面的一个属性设置过渡动画,比如:transition: width 2s;

祥见:CSS3 transition 属性

  • transition-property 规定设置过渡效果的 CSS 属性的名称。
  • transition-duration 规定完成过渡效果需要多少秒或毫秒。
  • transition-timing-function规定速度效果的速度曲线。
  • transition-delay定义过渡效果何时开始。

Transition 的属性

元素动画在出现和消失时各有 3 个阶段,可以为这些属性绑定自定义函数:

  • onEnter:进入 (出现) 开始时执行
  • onEntering:进入 (出现) 过程中执行
  • onEntered:进入 (出现) 结束执行
  • onExit:离开 (消失) 时执行
  • onExiting:离开 (消失) 过程中执行
  • onExited:离开 (消失) 结束执行

其他属性介绍:

  • addEndListener:属性可以监听出现的 3 个阶段执行完成或消失的 3 个阶段执行完成时执行该函数监听的自定义函数。
  • unmountOnExit:为 true 代表退出的时候移除 dom,也就是该元素 dom 动画执行完后直接删除该元素节点
  • appear:渲染的时候就直接执行动画,默认 false
  • enter:设为 true 后,动画进入 (出现) 的三个阶段,前两个阶段 onEnter,onEntering 先执行,然后延迟一段时间再执行 onEntered,可以简单的理解为动画进入(出现) 时有个延迟
  • exit:设为 true 后,动画离开 (消失) 的三个阶段,前两个阶段 onExit,onExiting 先执行,然后延迟一段时间再执行 onExited,可以简单的理解为动画离开(消失) 时有个延迟
  • timeout:为上面的 appear,enter,exit 设置延迟时间
  • in:动画进入 (出现),离开(消失) 交替执行,点一下动画生效,再点一下动画失效

使用方法

<Transition> 标签可是设置上面那些属性。标签内容包裹一个箭头函数,该函数有一个参数 state(参数名随意设置), 返回值就是要实现动画效果的元素,该元素可以设置 style 样式。

案例一

此案例是我测试的案例,通过下拉框的透明度实现一个下拉框出现和消失的效果:

import React from 'react';
import {connect} from 'react-redux';
// 受到路由管控
import {withRouter} from 'react-router-dom';
import {Icon} from 'antd';
// 过渡动画
import Transition from 'react-transition-group/Transition';
//duration 设置延迟时间,下面的 timeout 属性使用
const duration = {
         appear:3000,
         enter: 3000,
         exit: 3000};
// 默认样式
const  defaultStyle = {
        //ease-in-out 规定以慢速开始和结束的过渡效果
        transition:`opacity ${3000}ms ease-in-out`,
        opacity:0,
    };
// 过渡样式
const  transitionStyles = {
        // 进入时 2,3 阶段动画,如果设置了延迟时间,会发现出现时立即透明度百分之 "0.5",然后三秒后透明度才为 "1"
        // 因为延迟时间 timeout 属性设置的 ``enter:3000`` 会在第三阶段生效
        entering:{opacity: 0.5},
        entered:{opacity:1},
        // 离开时 2,3 阶段
        exiting: {opacity: 0.5},
        exited: {opacity: 0}
    };

// 三个进入状态的事件,可以做你想做的事情
let onEnter = (node, isAppearing) => {console.log(isAppearing,node, 'onEnter')
};
let onEntering = (node, isAppearing) => {console.log(isAppearing,node, 'onEntering')
};
let onEntered = (node, isAppearing) => {console.log(isAppearing,node,'onEntered')
};

// 测试动画执行过程,何时结束
let done =() => {console.log('结束了')
};

// 三个退出的状态的事件
let onExit = (node) => {console.log('onExit')
};
let onExiting = (node) => {console.log('onExiting')
};
let onExited = (node) => {console.log('onExited',node)
};

let addaddEndListener = (node) => { // 原生时间 transition 运动的事件
    node.addEventListener('transitionend', this.done, false);
};

class NavTop extends React.Component{constructor(props,context){super(props,context);
        this.state = {in:false};
    }

    render() {
        return <header className='headerNavBox'>
            {/* 首页导航 */}
            <div className='homeBox'>
                <div className='baseBox clearfix' >
                    <h1 className='logo' > 大鱼资源网 </h1>
                    <Icon className='icon' type='bars' style={{fontSize:'.6rem'}} onClick={ev=>{
                        this.setState({in:!this.state.in})
                    }} />
                </div>
                {/* 下拉条,过渡动画 */}
                <Transition
                    onEnter={onEnter}
                    onEntering={onEntering}
                    onEntered={onEntered}

                    onExit={onExit}
                    onExiting={onExiting}
                    onExited={onExited}

                    addEndListener={this.addaddEndListener}// 添加动画执行完后执行的函数
                    unmountOnExit={true}// 动画消失后,元素 dom 节点也消失
                    appear={false}// 组件渲染就出现动画
                    enter={true}// 动画效果出现时延迟, 默认是 true
                    exit={true}// 动画效果消失时延迟
                    timeout={duration}// 设置延迟时间,准确的说应该是动画出现和消失的第三阶段延迟时间,因为前两个阶段会立即执行
                    in={this.state.in} >
                    {
                        state => {
                            // 打印状态变化分别是 onEnter,onEntering... 等 6 种,通过此处可以看出延迟时间是在第三阶段生效,前两个阶段会立即执行
                            console.log(state,'###',{...defaultStyle, ...transitionStyles[state]}, '###');
                            return <ul className='filterBox' style={{
                                ...defaultStyle,
                                // 根据 state 的变化,过渡动画的透明度随着变化
                                ...transitionStyles[state]
                            }} >
                                <li> 全部课程 </li>
                                <li>react 课程 </li>
                                <li>vue 课程 </li>
                                <li> 小程序课程 </li>
                            </ul>
                        }
                    }
                </Transition>
            </div>
        </header>;
    }
}

export default withRouter(connect()(NavTop));

案例一结束。

案例二

// 自己简单的封装了一个,该有的参数都由了,可以自行粘贴在自己的代码里面去试试。class Fade extends React.Component {constructor(props) {super(props);
  }
  done =() => {// console.log('结束了')
  }
  addaddEndListener = (node) => { // 原生时间 transition 运动的事件
    node.addEventListener('transitionend', this.done, false);
  }

  // 三个进入状态的事件,可以做你想做的事情
  onEnter = (node, isAppearing) => {console.log(isAppearing, 'onEnter')
  }
  onEntering = (node, isAppearing) => {console.log(isAppearing, 'onEntering')
  }
  onEntered = (node, isAppearing) => {console.log(isAppearing, 'onEntered')
  }

  // 三个退出的状态的事件
  onExit = (node) => {console.log('onExit')
  }
  onExiting = () => {console.log('onExiting')
  }
  onExited = () => {console.log('onExited')
    this.props.self()}
  render() {const { in: inProp, dur} = this.props;
    const defaultStyle = {transition: `transform ${300}ms ease-in-out, opacity ${300}ms ease-in-out`,
      transform: 'translateX(100px)',
      opacity: '0'
    }

    const transitionStyles = {entering: { transform: 'translateX(100px)', opacity: '0'},
      entered:  {transform: 'translateX(0px)', opacity: '1' },
      exiting: {transform: 'translateX(0px)', opacity: '1'},
      exited: {transform: 'translateX(0px)', opacity: '0'}
    };
    const duration = {
      enter: 300,
      exit: 300,
    }
    // 上面的都是基本参数,样式的转变以及时间的设定,具体的可以看官网文档
    // 样式也可以写成 className 例如 <MyComponent className={`fade fade-${status}`} />
    return (
      <Transition 
        onEnter={this.onEnter}
        onEntering={this.onEntering}
        onEntered={this.onEntered}

        onExit={this.onExit}
        onExiting={this.onExiting}
        onExited={this.onExited}

        addEndListener={this.addaddEndListener} 
        in={inProp} 
        unmountOnExit={false} // 为 true 代表退出的时候移除 dom
        appear={true} // 为 true  渲染的时候就直接执行动画,默认 false,timeout={duration}
      >
        {
          state => {console.log(state, '###') // 你可以很直观的看到组件加载和卸载时候的状态
            return(
              <div style={{
                ...defaultStyle,
                ...transitionStyles[state]
              }}>
                {this.props.children}
              </div>
            )
          }
        }
      </Transition>
    );
  }
}

案例二结束。

参考网址

官方案例

react 官网动画库(react-transition-group)的新写法

退出移动版