React: Animation

49659 ワード

DIsplay——表示と非表示


classとpropsの判断を利用してbackdropを表示/非表示に変換する.modal
.CloseModal{
    display: none;
}

.OpenModal{
    display: block;
}
const modal = (props) => {
    const cssClasses=["Modal",props.show?"OpenModal":"CloseModal"];

    return (
        <div className={cssClasses.join(" ")}>
            <h1>A Modal</h1>
            <button className="Button" onClick={props.closed}>Dismiss</button>
        </div>
    );
};

backDrop
.CloseBackdrop{
    display: none;
}

.OpenBackdrop{
    display: block;
}
const backdrop = (props) => {

    const cssClasses=["Backdrop",props.show?"OpenBackdrop":"CloseBackdrop"];
    return(
        <div className={cssClasses.join(" ")}></div>
    );
};

app stateとbutton制御backdropの表示非表示を設定
class App extends Component {
  state={
    ShowModal:false
  };    
  OpenModal=()=>{
      this.setState({ShowModal:true})
    } 

    CloseModal=()=>{
      this.setState({ShowModal:false})
    }
  render() {  
    return (
      <div className="App">
        <h1>React Animations</h1>
        <Modal 
          show={this.state.ShowModal}
          closed={this.CloseModal}
          />
        <Backdrop 
          show={this.state.ShowModal}
          />
        <button 
          className="Button"
          onClick={this.OpenModal}
          >Open Modal</button>
        <h3>Animating Lists</h3>
        <List />
      </div>
    );
  }
}

Css Transitions


CSS:設定opacity:0イコールdisplay:none設定opacity:1イコールdisplay:block
.CloseModal{
    opacity: 0;
    transform: translateY(-200%);
}

.OpenModal{
    opacity: 1;
    transform: translateY(0);
}

Transitionは、すべてのopacityとtransformにダイナミックエフェクトを追加します.
    transition: all 0.3s ease-out;

Animation+keyframes


transitionの各期間の制御を実現

.CloseModal{
    animation: close 0.4s ease-out forwards;
}

.OpenModal{
    animation: open 0.4s ease-out forwards;
}


@keyframes open{
    0%{
        opacity: 0;
        transform: translateY(-200%);
    }

    50%{
        opacity: 0.5;
        transform: translateY(100%);
    }

    100%{
        opacity: 1;
        transform: translateY(0);
    }
}


@keyframes close{
    100%{
        opacity: 0;
        transform: translateY(-200%);
    }

    50%{
        opacity: 0.5;
        transform: translateY(100%);
    }

    0%{
        opacity: 1;
        transform: translateY(0);
    }
}

制限css transition&animations Limitation


すべての要素はdomにありますが、opacityは0なので隠されています.表示されない要素がrenderされないようにreactでstateに従ってrenderの内容を設定します.しかし、modalはappでrenderされず、cssで設定されたclassも表示されず、直接消えるため、closeのanimationは無視されます.

そのためReact transition groupを用いて最適化する必要がある


https://github.com/reactjs/react-transition-group
import {Transition} from 'react-transition-group';

Transitionの使い方:小包を1つ{function=>(JSX)}
<Transition
          in={this.state.ShowToggle}
          timeout={300}
          mountOnEnter
          unmountOnExit
        >
          {          
            (state)=>(
            <div 
            style={{
              backgroundColor:"red",
              width:100,
              height:100,
              margin:"auto",
              transition: 'opacity 0.3s ease-out',
              opacity: state==='exiting'||state==='entering'? 0:1
          }}></div>
          )}

        </Transition>

Transitionのstateを下層に転送し、cssカスタマイズを行う
<Transition
          in={this.state.ShowModal}
          timeout={300}
          mountOnEnter
          unmountOnExit
        >
          {
            state=>(
            <Modal 
              show={state}
              closed={this.CloseModal}
            />  
            )
          }

        </Transition>  

下層:
const modal = (props) => {
    const cssClasses=["Modal",
        props.show==='entering'?"OpenModal":
        props.show==='exiting'? "CloseModal"
        : null];

    return (
        <div className={cssClasses.join(" ")}>
            <h1>A Modal</h1>
            <button className="Button" onClick={props.closed}>Dismiss</button>
        </div>
    );
};

Transitionをcomponentに入れる

import React from 'react';

import './Modal.css';
import {Transition} from 'react-transition-group';


const modal = (props) => {
    return (
    <Transition
        in={props.show}
        timeout={300}
        mountOnEnter
        unmountOnExit
      >
    {state=>{
            const cssClasses=["Modal",
            state==='entering'?"OpenModal":
            state==='exiting'? "CloseModal"
            : null];
        return(
        <div className={cssClasses.join(" ")}>
            <h1>A Modal</h1>
            <button className="Button" onClick={props.closed}>Dismiss</button>
        </div>
        );
    }}
    </Transition>
    );
};

export default modal;

Timingの設定


TransitionのTimeoutはenteringとexitingの時間を指す.この時間がcssでtransitionの時間よりはるかに小さい場合、timeout時間が過ぎた後にenteredまたはexited状態に直接到達し、完全なアニメーションを完了できません.Timeout timeoutのenterとexitを設定すると、openとcloseのtimeout時間をそれぞれ設定できます.
        <Transition
          in={this.state.ShowToggle}
          timeout={300}
          mountOnEnter
          unmountOnExit
        >
          {          
            (state)=>(
            <div 
            style={{
              backgroundColor:"red",
              width:100,
              height:100,
              margin:"auto",
              transition: 'opacity 0.3s ease-out',
              opacity: state==='exiting'||state==='entering'? 0:1
          }}></div>
          )}
        </Transition>

Transitionのevent&callbackの設定


onEnter={()=>>console.log("OnEnter")}onEntering={()=>>console.log("OnEntering")}onEntered={()=>>console.log("OnEntering")}onExit={()=>console.log(""""""""""""""""""""")}onExiting={()=>>console.log(")}onExited={()=>>>console.log(")}6時間帯("Exited")}6時間帯"}6時間帯(""""""""""""""""""""""";
<Transition
          in={this.state.ShowToggle}
          timeout={300}
          mountOnEnter
          unmountOnExit
          onEnter={()=>console.log("OnEnter")}
          onEntering={()=>console.log("OnEntering")}
          onEntered={()=>console.log("OnEntering")}
          onExit={()=>console.log("OnExit")}
          onExiting={()=>console.log("OnExiting")}
          onExited={()=>console.log("OnExited")}
        >

CSSTransition


CSSTansitionでclassnamesを設定し、cssファイルでname-enter-activeとname-exit-acitveを設定してアニメーションを完了します.
import React from 'react';

import './Modal.css';
import {Transition,CSSTransition} from 'react-transition-group';


const modal = (props) => {
    const AnimationTime={
        enter:300,
        exit:1000
    }
    return (
    <CSSTransition
        in={props.show}
        timeout={AnimationTime}
        mountOnEnter
        unmountOnExit
        classNames="My-Modal"
      >
        <div className="Modal">
            <h1>A Modal</h1>
            <button className="Button" onClick={props.closed}>Dismiss</button>
        </div>
    </CSSTransition>
    );
};

export default modal;
.My-Modal-enter-active{
    animation: open 0.4s ease-out forwards;
}
.My-Modal-exit-active{
    animation: close 1s ease-out forwards;
}

カスタムClassName


classNameで各パラメータを設定します.
<CSSTransition
        in={props.show}
        timeout={AnimationTime}
        mountOnEnter
        unmountOnExit
        classNames={{
            enterActive:"OpenModal",
            exitActive:"CloseModal"
        }}
      >
        <div className="Modal">
            <h1>A Modal</h1>
            <button className="Button" onClick={props.closed}>Dismiss</button>
        </div>
    </CSSTransition>

ulliにanimationを設定する


TransitionGroupを使用してCSSTransitionをラップします.
import {TransitionGroup,CSSTransition, Transition} from 'react-transition-group';

cssで対応するtrunk classnameにanimationを設定すればよい.
render () {
        const listItems = this.state.items.map( (item, index) => (
            <CSSTransition
                key={index}
                classNames="fade"
                timeout={300}
            >
            <li 
                
                className="ListItem" 
                onClick={() => this.removeItemHandler(index)}>{item}</li>
            </CSSTransition>
        ) );

        return (
            <div>
                <button className="Button" onClick={this.addItemHandler}>Add Item</button>
                <p>Click Item to Remove.</p>
                <TransitionGroup 
                    component="ul"
                    className="List"
                    >
                    {listItems}
                </TransitionGroup>
            </div>
        );
    }
.fade-enter{
    opacity: 0;
}

.fade-enter-active{
    opacity: 1;
    transition: opacity 0.3s ease-out;
}

.fade-exit{
    opacity: 1;
}

.fade-exit-active{
    opacity: 0;
    transition: opacity 0.3s ease-out;
}

その他のanimation library


More on CSS Transitions: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions More on CSS Animations: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations More on ReactTransitionGroup: https://github.com/reactjs/react-transition-group Alternative => React Motion: https://github.com/chenglou/react-motion Alternative => React Move: https://github.com/react-tools/react-move Animating Route Animations: https://github.com/maisano/react-router-transition