React中组件间过渡动画如何实现?

简介: React中组件间过渡动画如何实现?

一、是什么

在日常开发中,页面切换时的转场动画是比较基础的一个场景

当一个组件在显示与消失过程中存在过渡动画,可以很好的增加用户的体验

react中实现过渡动画效果会有很多种选择,如react-transition-groupreact-motionAnimated,以及原生的CSS都能完成切换动画


二、如何实现

react中,react-transition-group是一种很好的解决方案,其为元素添加enterenter-activeexitexit-active这一系列勾子

可以帮助我们方便的实现组件的入场和离场动画

其主要提供了三个主要的组件:

  • CSSTransition:在前端开发中,结合 CSS 来完成过渡动画效果
  • SwitchTransition:两个组件显示和隐藏切换时,使用该组件
  • TransitionGroup:将多个动画组件包裹在其中,一般用于列表中元素的动画


CSSTransition

其实现动画的原理在于,当CSSTransitionin属性置为true时,CSSTransition首先会给其子组件加上xxx-enterxxx-enter-activeclass执行动画

当动画执行结束后,会移除两个class,并且添加-enter-doneclass

所以可以利用这一点,通过csstransition属性,让元素在两个状态之间平滑过渡,从而得到相应的动画效果

in属性置为false时,CSSTransition会给子组件加上xxx-exitxxx-exit-activeclass,然后开始执行动画,当动画结束后,移除两个class,然后添加-enter-doneclass

如下例子:


export default class App2 extends React.PureComponent {
  state = {show: true};
  onToggle = () => this.setState({show: !this.state.show});
render() {
const {show} = this.state;
return (
 <div className={'container'}>
 <div className={'square-wrapper'}>
 <CSSTransition
 in={show}
 timeout={500}
 classNames={'fade'}
 unmountOnExit={true}
           >
 <div className={'square'} />
 </CSSTransition>
 </div>
 <Button onClick={this.onToggle}>toggle</Button>
 </div>
     );
   }
 }


对应css样式如下:


.fade-enter {
opacity: 0;
transform: translateX(100%);
}
.fade-enter-active {
opacity: 1;
transform: translateX(0);
transition: all 500ms;
 }
 .fade-exit {
 opacity: 1;
 transform: translateX(0);
 }
 .fade-exit-active {
 opacity: 0;
 transform: translateX(-100%);
 transition: all 500ms;
 }


SwitchTransition

SwitchTransition可以完成两个组件之间切换的炫酷动画

比如有一个按钮需要在onoff之间切换,我们希望看到on先从左侧退出,off再从右侧进入

SwitchTransition中主要有一个属性mode,对应两个值:

  • in-out:表示新组件先进入,旧组件再移除;
  • out-in:表示就组件先移除,新组建再进入

SwitchTransition组件里面要有CSSTransition,不能直接包裹你想要切换的组件

里面的CSSTransition组件不再像以前那样接受in属性来判断元素是何种状态,取而代之的是key属性

下面给出一个按钮入场和出场的示例,如下:


 import { SwitchTransition, CSSTransition } from "react-transition-group";
export default class SwitchAnimation extends PureComponent {
constructor(props) {
super(props);
this.state = {
isOn: true
    }
   }
 render() {
 const {isOn} = this.state;
 return (
 <SwitchTransition mode="out-in">
 <CSSTransition classNames="btn"
 timeout={500}
 key={isOn ? "on" : "off"}>
           {
 <button onClick={this.btnClick.bind(this)}>
             {isOn ? "on": "off"}
 </button>
         }
 </CSSTransition>
 </SwitchTransition>
     )
   }
 btnClick() {
 this.setState({isOn: !this.state.isOn})
   }
 }


css文件对应如下:


.btn-enter {
transform: translate(100%, 0);
opacity: 0;
}
.btn-enter-active {
transform: translate(0, 0);
opacity: 1;
transition: all 500ms;
 }
 .btn-exit {
 transform: translate(0, 0);
 opacity: 1;
 }
 .btn-exit-active {
 transform: translate(-100%, 0);
 opacity: 0;
 transition: all 500ms;
 }


TransitionGroup

当有一组动画的时候,就可将这些CSSTransition放入到一个TransitionGroup中来完成动画

同样CSSTransition里面没有in属性,用到了key属性

TransitionGroup在感知children发生变化的时候,先保存移除的节点,当动画结束后才真正移除

其处理方式如下:

  • 插入的节点,先渲染dom,然后再做动画
  • 删除的节点,先做动画,然后再删除dom

如下:


import React, { PureComponent } from 'react'
import { CSSTransition, TransitionGroup } from 'react-transition-group';
export default class GroupAnimation extends PureComponent {
constructor(props) {
super(props);
this.state = {
friends: []
     }
   }
 render() {
 return (
 <div>
 <TransitionGroup>
           {
             this.state.friends.map((item, index) => {
               return (
 <CSSTransition classNames="friend" timeout={300} key={index}>
 <div>{item}</div>
 </CSSTransition>
               )
             })
           }
 </TransitionGroup>
 <button onClick={e => this.addFriend()}>+friend</button>
 </div>
     )
   }
 addFriend() {
 this.setState({
 friends: [...this.state.friends, "coderwhy"]
     })
   }
 }


对应css如下:


.friend-enter {
transform: translate(100%, 0);
opacity: 0;
}
.friend-enter-active {
transform: translate(0, 0);
opacity: 1;
transition: all 500ms;
 }
 .friend-exit {
 transform: translate(0, 0);
 opacity: 1;
 }
 .friend-exit-active {
 transform: translate(-100%, 0);
 opacity: 0;
 transition: all 500ms;
 }
相关文章
|
6月前
|
前端开发 Java API
【第49期】一文了解React动画
【第49期】一文了解React动画
170 0
|
6月前
|
设计模式 前端开发 数据可视化
【第4期】一文了解React UI 组件库
【第4期】一文了解React UI 组件库
362 0
|
6月前
|
存储 前端开发 JavaScript
【第34期】一文学会React组件传值
【第34期】一文学会React组件传值
77 0
|
6月前
|
前端开发
【第31期】一文学会用React Hooks组件编写组件
【第31期】一文学会用React Hooks组件编写组件
79 0
|
6月前
|
存储 前端开发 JavaScript
【第29期】一文学会用React类组件编写组件
【第29期】一文学会用React类组件编写组件
76 0
|
6月前
|
前端开发 开发者
【第26期】一文读懂React组件编写方式
【第26期】一文读懂React组件编写方式
64 0
|
6月前
|
资源调度 前端开发 JavaScript
React 的antd-mobile 组件库,嵌套路由
React 的antd-mobile 组件库,嵌套路由
122 0
|
6月前
|
存储 前端开发 中间件
React组件间的通信
React组件间的通信
52 1
|
6月前
|
前端开发 JavaScript API
React组件生命周期
React组件生命周期
119 1
|
6月前
|
存储 前端开发 JavaScript
探索 React Hooks 的世界:如何构建出色的组件(下)
探索 React Hooks 的世界:如何构建出色的组件(下)
探索 React Hooks 的世界:如何构建出色的组件(下)