最近对前端动画方案作了一些调研,想找到一个简单且易复制的方案在React组件中使用(也就是用复制粘贴解决80%的问题),最终选择官方的react-transition-group加animate.csscss
本文并不打算介绍 CSS 动画可是推荐一些资源,若是你对CSS 动画比较陌生也先阅读下面的资源html
animate.css 是一个出色的样式库,提供了各类经常使用的CSS 动画效果,简易的例子以下基本见名知意这里就不作额外的解释了前端
<div class="animated bounce delay-2s">Example</div>
不过大多数的时候咱们必然不须要引入所有样式,甚至咱们可能只想copy一个动画效果,在这里我fork 了一份 animate.css 而后在其构建的过程当中添加了sourcemap方便copyreact
带sourcemap的DEMO站点打开控制台开启复制粘贴之旅css3
CSSTransiotn 会在动画的生命周期内为其指定的子元素添加表明其处于指定生命周期的class
假设有以下DEMO
当 CSSTransition
的 in
属性值切换时true
的时候会依次给chidern
添加 fade-enter, fade-enter-active, fade-enter-done。
当 CSSTransition
的 in
属性值切换时false
的时候会依次给chidern
添加 fade-exit, fade-exit-active, fade-exit-done。git
其中 -enter-active
紧随 -enter
以后添加而且跟-enter
同时存在,而-enter-done
在动画结束时添加而且与-enter-active
和enter
互斥,exit
同理。github
因此当咱们要利用CSSTransition实现动画效果的时候,只须要定义出对应时间点出现的class
样式便可,须要注意的俩点web
timeout
决定因此所写的样式during
必须跟与其对应(以后咱们会对CSSTransition进行简单封装解决这个问题)CSSTransition
决定前缀的参数是classNames
不是className
<CSSTransition in={fadeIn} timeout={2000} unmountOnExit classNames="fade" onEnter={this.onEnter} onEntered={this.onEntered} onExit={this.onExit} onExited={this.onExited} > <div className="demo" >fade-{fadeIn ? 'in' : 'out'}</div> </CSSTransition>
虽然在动画的执行的生命周期内出现了6个关键点可是使用css3 animation
实现动画效果时咱们只需操做俩个时间点 -enter
和 -exit
就ok了,以后要作的就是在animate.css
copy 对应的代码less
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } } .fade { &-enter { animation-name: fadeIn; animation-duration: 2000ms; } &-exit { animation-name: fadeOut; animation-duration: 2000ms; } }
利用React.cloneElement
对为CSSTransition
默认添加 animated
class,而且经过设置内联的样式的方式让动画效果结束的时间跟timeout
字段一致前端构建
animated
为了为动画设置一些默认的样式,好比像下面这样默认设置动画时长为1s
animation-fill-mode
为 both
.animated { animation-duration: 1s; animation-fill-mode: both; } @media (print), (prefers-reduced-motion) { .animated { animation: unset !important; transition: none !important; } }
import React from 'react' import { CSSTransition } from 'react-transition-group' let count = 0 export default class Animation extends React.Component { static defaultProps = { in: true, timeout: 1000,// 与 .animate 中设置的默认时间对应 unmountOnExit: true, classNames: '', onEnter () {}, onEntered () {}, onExit () {}, onExited () {} } constructor () { super() this.count = count++ } onEnter = () => { console.time(`enter${this.count}`) this.props.onEnter() } onEntered = () => { console.timeEnd(`enter${this.count}`) this.props.onEntered() } onExit = () => { console.time(`exit${this.count}`) this.props.onExit() } onExited = () => { console.timeEnd(`exit${this.count}`) this.props.onExited() } render () { const { in: isIn, timeout, unmountOnExit, classNames, children } = this.props const { props: { className = '', style = {} } } = children return ( <CSSTransition in={isIn} timeout={timeout} unmountOnExit={unmountOnExit} classNames={classNames} onEnter={this.onEnter} onEntered={this.onEntered} onExit={this.onExit} onExited={this.onExited} > {React.cloneElement(children, { className: `animated ${className}`, style: { ...{ '--webkit-animation-duration': `${timeout}ms`, animationDuration: `${timeout}ms` }, ...style } })} </CSSTransition> ) } }