react 动画难写?试试 react 版 transformjs

简介

transformjs 在非 react 领域用得风生水起,那么 react 技术栈的同学能用上吗?答案是可以的。junexie 童鞋已经造了个 react 版本

动画实现方式

传统 web 动画的两种方式

  1. 纯粹的 CSS3 :如:transition/animation+transform(大名鼎鼎的 animate.css)
  2. JS + CSS3 transition 或者 animation:这里第一种一样,只是通过 js 里 add class 和 remove class 去增加或者移除对应的动画
  3. 纯粹 JS 控制时间轴:第一和第二种都是自带时间轴,使用 setInterval / setTimeout / requestAnimationFrame 不断地修改 DOM 的 style 属性产生动画

对应在 react 中

使用 CSS3

  • 使用 ReactCSSTransitionGroup 来实现
  • 相关动画的 class 都有对应的 state,修改 state 相当于增加或者移除 class,也就相当于 js 里 add class 和 remove class 去增加或者移除对应的动画

纯粹 JS 控制时间轴

  • 仍然使用 setInterval / setTimeout / requestAnimationFrame,修改某个 state 值,然后映射到 component 的 style 上。

这里很明显,方案 1 和方案 2 可应对简单场景(如没有 prop change 回调等),方案 3 可编程性最大,最灵活,可以适合复杂的动画场景或者承受复杂的交互场景。

安装

1

npm install css3transform-react

API

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

//set "translateX", "translateY", "translateZ", "scaleX", "scaleY", "scaleZ", "rotateX", "rotateY", "rotateZ", "skewX", "skewY", "originX", "originY", "originZ"

render() {

    return (

        <Transform

          translateX={100}

          scaleX={0.5}

          originX={0.5}>

          <div>sth</div>

        </Transform>

    );

}

// you can also use other porps, such as "className" or "style"

render() {

    return (

        <Transform

          translateX={100}

          className="ani"

          style={{width: '100px', background: 'red'}}

          <div>sth</div>

        </Transform>

    );

}

通过上面的声明,就可以设置或者读取"translateX", "translateY", "translateZ", "scaleX", "scaleY", "scaleZ", "rotateX", "rotateY", "rotateZ", "skewX", "skewY", "originX", "originY", "originZ"!

方便吧!

使用姿势

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

import React, { Component } from 'react';

import { render } from 'react-dom';

import Transform from '../../transform.react.js';

class Root extends Component {

  constructor(props, context) {

    super(props, context);

    this.state = {

      el1: {rotateZ: 0},

      el2: {rotateY: 0}

    };

    this.animate = this.animate.bind(this);

  }

  animate() {

    this.setState({

      el1: {rotateZ: this.state.el1.rotateZ + 1},

      el2: {rotateY: this.state.el2.rotateY + 1}

    }, () => {

      requestAnimationFrame(this.animate);

    });

  }

  componentDidMount() {

    setTimeout(this.animate, 500);

  }

  render() {

    return (

      <div>

        <Transform rotateZ={this.state.el1.rotateZ} className="test" style={{'backgroundColor': 'green'}}>

          transformjs

        </Transform>

        <Transform rotateY={this.state.el2.rotateY} className="test" style={{'backgroundColor': 'red', 'left': '200px'}}>

          transformjs

        </Transform>

      </div>

    );

  }

}

render(

    <Root />,

    document.getElementById('root')

);

更加复杂的详细的使用代码可以看这里:PhyTouch/index.jsx at master · AlloyTeam/PhyTouch · GitHub

在线演示

http://alloyteam.github.io/AlloyTouch/transformjs/react/example/

性能对比

因为 react 版本会有 diff 过程,然后 apply diff to dom 的过程,state 改变不会整个 innerHTML 全部替换,所以对浏览器渲染来说还是很便宜,但是在 js 里 diff 的过程的耗时还是需要去 profiles 一把,如果耗时严重,不在 webworker 里跑还是会卡住 UI 线程导致卡顿,交互延缓等。所以要看一看 CPU 的耗时还是很有必要的。
主要是那上面的演示和传统的直接操作 dom 的方式对比。就是下面这种传统的方式:

1

2

3

4

5

6

7

8

9

10

11

var element1 = document.querySelector("#test1");

Transform(element1);

...

...

function animate() {

    element1.rotateZ++;

    ...

    requestAnimationFrame(animate);

}

animate();

对两种方式使用 chrome profiles 了一把。
先看总耗时对比

react:

传统方式:

  • react 在 8739 秒内 CPU 耗时花费了近似 1686ms
  • 传统方式在 9254ms 秒内 CPU 耗时花费近似 700ms

在不进行 profiles 就能想象到 react 是一定会更慢一些,因为 state 的改变要走把 react 生命周期走一遍,但是可以看到 react 的耗时还是在可以接受的范围。但是,我们还是希望找到拖慢的函数来。
那么在使用 transformjs react 版本中,哪个函数拖了后腿?展开 profiles tree 可以看到:

就是它了。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

/**

       * Reconciles the properties by detecting differences in property values and

       * updating the DOM as necessary. This function is probably the single most

       * critical path for performance optimization.

       *

       * TODO: Benchmark whether checking for changed values in memory actually

       *       improves performance (especially statically positioned elements).

       * TODO: Benchmark the effects of putting this at the top since 99% of props

       *       do not change for a given reconciliation.

       * TODO: Benchmark areas that can be improved with caching.

       *

       * @private

       * @param {object} lastProps

       * @param {object} nextProps

       * @param {?DOMElement} node

       */

      _updateDOMProperties: function (lastProps, nextProps, transaction) {

打开对应的代码可以看到。注释里已经写了这是优化重点。

开始使用吧

官方网站:http://alloyteam.github.io/AlloyTouch/transformjs/

Github 地址:PhyTouch/transformjs at master · AlloyTeam/PhyTouch · GitHub

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

短暂又灿烂的

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值