Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React 的动画过渡库 - React-Transition-group #45

Open
lulujianglab opened this issue Mar 22, 2019 · 0 comments
Open

React 的动画过渡库 - React-Transition-group #45

lulujianglab opened this issue Mar 22, 2019 · 0 comments
Labels

Comments

@lulujianglab
Copy link
Owner

在开发中实现动画的方法有很多,不管是 react 还是 vue 都有开源的动画组件库来更加方便的动画实现效果

react 动画组件库是 React-Transition-group,在说这个组件库之前,我们先来看下借助 CSS3 实现最基本的动画样式

CSS3 实现动画样式

constructor(props) {
  super(props)
  this.state = {
    show: true
  }
  this.handleToggle = this.handleToggle.bind(this)
}

render() {
  return (
    <Fragment>
      <div className={this.state.show ? 'show' : 'hide'}>hello</div>
      <button onClick={this.handleToggle}>toggle</button>
    </Fragment>
  );
}

handleToggle() {
  this.setState({
    show: this.state.show ? false : true
  })
}
.show {
  opacity: 1;
  transition: all 1s ease-in;
}

.hide {
  opacity: 0;
  transition: all 1s ease-in;
}

这样在浏览器中通过控制 toggle,就可以看到 hello 若隐若现了,就借助了 CSS3 实现了最基本的动画样式

使用 react-transition-group 实现动画

在 github 中搜索 react-transition-group ,可以看到 star 最多的项目,就是 react-transition-group

先安装依赖 npm install react-transition-group --save

然后在项目中引入 import { CSSTransition } from 'react-transition-group'

可以看到官网的demo

classNames="fade" applies fade-enter, fade-enter-active, fade-enter-done, fade-exit, fade-exit-active, fade-exit-done, fade-appear, and fade-appear-active.

Transition

过渡组件 ( Transiton ) 允许您用一个简单的声明性 API 描述随着时间的推移从一个组件状态到另一个组件状态的转换

默认展示组件某个特定状态的样式,而不是创建渐变动画

<Transition
  in={this.state.show}
  timeout={1000}
  // unmountOnExit
>
  {state=>{
    if(state === 'entering' || state === 'entered')
      return <div className="on">{state}</div>
    else 
      return <div className="off">{state}</div>
  }}
</Transition>
<button onClick={this.handleAddItem}>toggle {`${this.state.show}`}</button>

Transition 中间传入一个函数,也就是属性 children ,并获得一个参数 state,

state 包含了内部组件的 transition 状态,分别有

  • entering
  • entered
  • exiting
  • exited
  • unmounted

上述 🌰 的意思可以理解为

你设置的时间是 1000ms,当 in 从 false 变成 true 的时候, 显示 <div className="on">{state}</div>enteringentered 的状态 ), 相反的,当 in 从 true 变成 false 的时候,1000ms 之后, 切换到 <div className="off">{state}</div>exitingexited 的状态 )

运行原理

从头来看,它其实就是一个状态机,跟动画没什么关系,所以它的名字也是叫 Transition

有点像路由,在不同的组件中选择一个渲染,唯一的区别是,它只有4个路由选项:

进入 ( in === true )时,url 是 entering,1000ms 后,url 变成 entered

退出 ( in ===false ) 时,url 是 exiting,1000ms 后,url 变成 exited

然后加上 css ease-in-out 就成了动画

CSSTransition

展示组件从状态到另一个状态的动态变化,需要定义 className 和相关样式

最常用的是用来动画一个组件的安装和卸载,但也可以用来描述在适当的过渡状态

可以将我们之前用 CSS3 写的样式修改为

render() {
  return (
    <Fragment>
      <CSSTransition
        in={this.state.show}
        timeout={1000}
        // 前缀名注意S
        classNames='fade'
      >
        <div>hello</div>
      </CSSTransition>
      <button onClick={this.handleToggle}>toggle</button>  
    </Fragment>
  )
}

handleToggle() {
  this.setState({
    show: this.state.show ? false : true
  })
}
.fade-enter {
  opacity: 0;
}

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

/* 入场动画执行完毕后,保持状态 */
.fade-enter-done {
  opacity: 1;
}

.fade-exit {
  opacity: 1;
}

.fade-exit-active {
  opacity: 0;
  transition: opacity 1s ease-in;
}

.fade-exit-done {
  opacity: 0;
}

这样就可以实现和之前相同的动画效果了

咋一看虽然稍微复杂了点,但是它可以带给我们很多新的特效

比如参数 intrue or false,代表了是’淡入’状态,还是’淡出’状态

timeout 代表了整个的持续时间

unmountOnExit 属性,添加到代码中,会发现当我们点隐藏的时候,对应的 DOM 被移出了,点显示的时候,DOM 又出来了

借助 react-transition-group 这个库,实现起来非常简单

继续看它的文档,这个库提供了很多钩子函数

image

假设当这个 hello 显示出来之后,希望它的颜色能变成红色,现在实现就变得很简单了

只需要在入场动画结束之后,将 color 变成 red

.fade-enter-done {
  opacity: 1;
  color: red
}

还可以用 js 的方式来实现,怎么做呢?

CSSTransition 组件中添加一个钩子onEntered

<CSSTransition
  in={this.state.show}
  timeout={1000}
  classNames='fade'
  unmountOnExit
  onEntered={(el) => {el.style.color='blue'}}
>
  <div>hello</div>
</CSSTransition>

钩子和生命周期函数是一个东西,就是在某个时刻会自动执行的函数

onEntered 钩子什么时候会自动执行呢?就是当入场动画结束之后,就会被执行

el 就是指的内部的 div 元素

如果希望第一次展示的时候也有动画效果,应该怎么办呢?

同样也需要在 CSSTransition 组件中添加一个 appear={true} ,同时在入场动画的第一帧添加 fade-appear ,同时在入场动画的第二帧以及整个过程中添加 fade-appear-active

/* enter是入场前的刹那(点击按钮),appear指页面第一次加载前的一刹那(自动) */
.fade-enter, .fade-appear {
  opacity: 0;
}

/* enter-active指入场后到入场结束的过程,appear-active则是页面第一次加载自动执行 */
.fade-enter-active, .fade-appear-active {
  opacity: 1;
  transition: opacity 1s ease-in;
}

这些也就是 react-transition-group 这个库比较核心的内容,其他更复杂的方法可以查阅 Transition

TransitionGroup

如果要做多个元素的动画切换呢?

这个时候就要用到 TransitionGroup

TransitionGroup 实际上就是实现多个Transition 或者CSSTransition组合的效果

用来管理一些列组件的动画,例如列表

首先引入这个组件 import TransitionGroup from 'react-transition-group'

constructor(props) {
  super(props)
  this.state = {
    data: []
  }
  this.handleAddItem = this.handleAddItem.bind(this)
}

render() {
  return (
    <Fragment>
      <TransitionGroup>
      {
        this.state.data.map((item, index) => {
          return (
            <CSSTransition
              timeout={1000}
              classNames='fade'
              unmountOnExit
              onEntered={(el) => {el.style.color='blue'}}
              appear={true}
              key={index}
            >
              <div>{item}</div>
            </CSSTransition>
          )
        })
      }
      </TransitionGroup>
        <button onClick={this.handleAddItem}>toggle</button>
    </Fragment>
  )
}

handleAddItem() {
  this.setState((prevState) => {
    return {
      data: [...prevState.data, 'item']
    }
  })
}

这样配合 TransitionGroupCSSTransition 就可以进行多个元素或者组件切换这样的动画效果了

完整代码

transition 动画

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant