一個簡單的構建React組件動畫方案

最近對前端動畫方案作了一些調研,想找到一個簡單且易複製的方案在React組件中使用(也就是用複製粘貼解決80%的問題),最終選擇官方的react-transition-groupanimate.csscss

我調研過的方案

  • anijs online demo 酷炫是很酷炫可是引用方式比較原始不太適合如今的前端構建流程和React
  • velocity.js 用jQuery $.animate() 相同的API 可是能夠不依賴 jQuery,這方式並非我所指望的故放棄
  • react-motion 很是酷炫若是要作複雜動畫目前來看非它莫屬,可是於我簡單易複製的指望不符
  • animate.css 用css 實現了各類常見的動畫效果,並且還有人封裝了react-animated-css
  • react-transition-group 官方的方案容易上手,可是應對複雜動畫比較無力,但是我並不作複雜的動畫所以這也就是心中的完美方案

關於CSS動畫

本文並不打算介紹 CSS 動畫可是推薦一些資源,若是你對CSS 動畫比較陌生也先閱讀下面的資源html

animate.css

animate.css 是一個出色的樣式庫,提供了各類經常使用的CSS 動畫效果,簡易的例子以下基本見名知意這裏就不作額外的解釋了前端

<div class="animated bounce delay-2s">Example</div>

不過大多數的時候咱們必然不須要引入所有樣式,甚至咱們可能只想copy一個動畫效果,在這裏我fork 了一份 animate.css 而後在其構建的過程當中添加了sourcemap方便copyreact

帶sourcemap的DEMO站點打開控制檯開啓複製粘貼之旅css3

an

簡單介紹一下react-transition-group 中的 CSSTransition

CSSTransiotn 會在動畫的生命週期內爲其指定的子元素添加表明其處於指定生命週期的class
假設有以下DEMO
CSSTransitionin屬性值切換時true的時候會依次給chidern 添加 fade-enter, fade-enter-active, fade-enter-done。
CSSTransitionin屬性值切換時false的時候會依次給chidern 添加 fade-exit, fade-exit-active, fade-exit-done。git

其中 -enter-active緊隨 -enter以後添加而且跟-enter 同時存在,而-enter-done在動畫結束時添加而且與-enter-activeenter互斥,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.csscopy 對應的代碼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;
  }
}

對CSSTransition 進行簡單封裝

利用React.cloneElement對爲CSSTransition 默認添加 animated class,而且經過設置內聯的樣式的方式讓動畫效果結束的時間跟timeout字段一致前端構建

animated爲了爲動畫設置一些默認的樣式,好比像下面這樣默認設置動畫時長爲1s animation-fill-modeboth

.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>
    )
  }
}

在線 DEMO

Edit animation-simple

相關文章
相關標籤/搜索