传统 web 动画的两种方式:纯粹的CSS3 :如:transition/animation+transform(大名鼎鼎的animate.css)
JS + CSS3 transition或者animation:这里第一种一样,只是通过js里add class和remove class去增加或者移除对应的动画纯粹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可编程性最大,最灵活,可以适合复杂的动画场景或者承受复杂的交互场景。
安装npm install css3transform-reactAPI//set
'translateX', 'translateY', 'translateZ', 'scaleX', 'scaleY', 'scaleZ',
'rotateX', 'rotateY', 'rotateZ', 'skewX', 'skewY', 'originX',
'originY', 'originZ'render() { return (
使用姿势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 (
在线演示http://alloyteam.github.io/AlloyTouch/transformjs/react/example/性能对比因为react版本会有diff过程,然后apply diff to dom的过程,state改变不会整个innerHTML全部替换,所以对浏览器渲染来说还是很便宜,但是在js里diff的过程的耗时还是需要去profiles一把,如果耗时严重,不在webworker里跑还是会卡住UI线程导致卡顿,交互延缓等。所以要看一看CPU的耗时还是很有必要的。主要是那上面的演示和传统的直接操作dom的方式对比。就是下面这种传统的方式: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可以看到:就是它了。 /** * 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) {打开对应的代码可以看到。注释里已经写了这是优化重点。