React动画API之ReactTransitionGroup用法

来源:互联网 发布:淘宝退货赚运费险 编辑:程序博客网 时间:2024/05/17 22:46

最近做的一个 React项目,因为频繁使用动画,考虑到快速开发和更好的可维护性,决定使用其他库来辅助,期间看到 React官网 提供的两个 API,决定尝试一下。

其中高级 API使用起来没什么难度,用过 Angular 或者 Vue 动画的人基本上扫一眼文档就能上手,但是 另外一个 底层API: ReactTransitionGroup,官网上几乎没什么介绍,只将几个生命周期的钩子函数罗列了一下,网上也没有什么关于这方面的讲解或者 Demo之类的东西,基本上都是围绕高级API ReactCSSTransitionGroup的。

因为需要对动画进行细粒度的控制,所以必须要用底层API才行,网上找不到使用的例子,没办法,只好自己亲自上手一个个实验,好在最后差不多算是弄清楚是怎么用的了。


钩子函数

React官网上对底层 API ReactTransitionGroup的解释:

ReactTransitionGroup是动画的基础。它通过 require('react-addons-transition-group)访问。当子级被声`明式的从其中添加或移除(就像上面的例子)时,特殊的生命周期挂钩会在它们上面被调用。

六个特殊的生命周期钩子函数如下:

  1. componentWillAppear()
    ReactTransitionGroup是动画的基础。它通过require('react-addons-transition-group')访问。当子级被声明式的从其中添加或移除(就像上面的例子)时,特殊的生命周期挂钩会在它们上面被调用。
  2. componentDidAppear()
    在 传给 componentWillAppear 的 回调 函数被调用后调用。
  3. componentWillEnter(callback)
    对于被添加到已存在的 TransitionGroup 的组件,它和 componentDidMount() 在相同时间被调用 。它将会阻塞其它动画发生,直到callback被调用。它不会在 TransitionGroup 初始化渲染时被调用。
  4. componentDidEnter()
    在传给 componentWillEnter的回调函数被调用之后调用。
  5. componentWillLeave(callback)
    在子级从 ReactTransitionGroup 中移除时调用。虽然子级被移除了,ReactTransitionGroup 将会保持它在DOM中,直到callback被调用。
  6. componentDidLeave()
    willLeave callback 被调用的时候调用(与 componentWillUnmount同一时间)

相信应该有不少人在看了上述官网讲解后依然是一头雾水,虽然六个钩子函数每一个都说的很仔细,但到底怎么用,可能还是不清楚,至于钩子函数中存在的回调函数 callback 到底是什么东西,就更不明白了。

对于这两点我也是很疑惑,不过实验了一番后,至于弄明白是怎么回事了,先上代码:

// Example.js  运动组件class Example extends React.Component {  componentWillAppear() {    console.log('componentWillAppear');  }  componentDidAppear() {    console.log('componentDidAppear');  }  componentWillEnter(callback) {    console.log('componentWillEnter');    document.querySelector('.flyBall').className += ' changeTop'    callback()  }  componentDidEnter() {    console.log('componentDidEnter');  }  componentWillLeave(callback) {    callback()  }  componentDidLeave() {    console.log('componentDidLeave');  }  render() {    return (      <div className="flyBall"></div>    )  }}

其中 changeTop样式为:

.changeTop {  animation: move 5s;}@keyframes move{from {left:0px;}to {left:200px;}}
// 引入运动组件import Example from 'Example'class Main extends React.Component {constructor(props) {    super(props)    this.state = {      show: false    }  }    render() {        return (          <div className="box1">            <ReactTransitionGroup component="div">              {                this.state.show && <Example/>              }            </ReactTransitionGroup>            <button onClick={this.changeOver.bind(this)}>Click</button>          </div>        )  }}

效果如下:
这里写图片描述

可以看到,动画的钩子函数,其实也就算是一种特殊的生命周期。

其中, 在本例中, componentWillAppearcomponentDidAppear这两个钩子函数没有执行,这是因为这两个钩子函数与 componentWillEntercomponentDidEnter这两个钩子函数是 互斥的,什么意思呢?

componentWillAppearcomponentDidAppear这两个钩子函数,只能在ReactTransitionGroup初始化的时候,被在刚开始就存在于ReactTransitionGroup中的子元素所触发,并且只能触发一次,后来追加进来的子元素只会触发 componentWillEntercomponentDidEnter,而不会触发 Enter

在初始化挂载,所有的ReactCSSTransitionGroup 子级将会 appear 但不 enter。然而,所有后来添加到已存在的 ReactCSSTransitionGroup 的子级将 enter但不 appear

说的简单点,同一个生命周期中,触发了 componentWillEntercomponentDidEnter,那么就不会触发 componentWillAppearcomponentDidAppear,反之亦然。

关于 callback需要说明的是,这东西我开始以为是自己定义的函数,然后再钩子函数中回调调用,但是却一直不明白该怎么将自己写的函数传进去,直到后来实验了几次才明白,原来这东西是内置的参数,根本不用管,如果你把这callback打印出来,就能看到其实它是这样的:

 console.log(callback, callback.name) // =>   "bound"  function(){[native code]}

是一个函数名为 bound的内置函数(native code)。

这个 callback的作用就是让特殊的生命周期继续往下执行,如果你不调用的话,那么就会阻滞动画的执行。

例如,如果你显式声明了:

componentWillLeave(callback) {   // 如果想要动画继续执行,必须调用下面代码,否则元素将被阻滞    callback() }

然后如果不在这个函数中执行 callback() 的话,那么元素就会被暂停住,这个时候,就算你的组件正常的生命周期中的 componentWillUnMount 已经执行完了,组件依旧不会被卸载掉。


用法

官网上关于如何使用此 API的说法很模糊,我稍微说一下。

<ReactTransitionGroup component="ul" className="animated-list">  ...</ReactTransitionGroup>

官网上给了这种使用方法,如果不指定 component,则默认在页面上渲染出一个 span元素,否则渲染出一个指定的元素,什么意思呢?

例如上述代码渲染出一个 ul元素,并且指定了其类名为 animated-list,其实是说上述代码会被完全替换为 <ul class="animated-list"></ul>这段代码。

你同样可以在其中添加子元素,子元素在渲染的时候会被保留。

<ReactTransitionGroup component="ul" className="animated-list">  <li>a li Element<li></ReactTransitionGroup>

上述会被替换为:

<ul class="animated-list">    <li>a li Element<li></ul>