簡介
transformjs在非react領域用得風生水起,那麼react技術棧的同學能用上嗎?答案是可以的。junexie童鞋已經造了個react版本。
動畫實現方式
傳統 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-react複製程式碼
API
//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"!
方便吧!
使用姿勢
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')
);複製程式碼
更加複雜的詳細的使用程式碼可以看這裡:github.com/AlloyTeam/A…
線上演示
alloyteam.github.io/AlloyTouch/…
效能對比
因為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) {複製程式碼
開啟對應的程式碼可以看到。註釋裡已經寫了這是優化重點。
開始使用吧
官方網站:alloyteam.github.io/AlloyTouch/…
Github地址:github.com/AlloyTeam/A…
任何問題和意見歡迎new issue給我們。
AlloyTeam大量招前端,有夢想愛學習的你請把簡歷傳送至 mhtml5@qq.com 。