React.js:非 CSS 动画
Posted
技术标签:
【中文标题】React.js:非 CSS 动画【英文标题】:React.js: Non-CSS animations 【发布时间】:2014-07-17 09:08:03 【问题描述】:React documentation 没有任何关于处理非 CSS 过渡动画的内容,例如滚动位置动画和 SVG 属性。
至于 CSS 过渡,有an add-on。
这里是a simple SVG example example:
/**
* @jsx React.DOM
*/
function animate(duration, onStep)
var start = Date.now();
var timer = id: 0;
(function loop()
timer.id = requestAnimationFrame(function()
var diff = Date.now() - start;
var fraction = diff / duration;
onStep(fraction);
if (diff < duration)
loop();
);
)();
return timer;
function lerp(low, high, fraction)
return low + (high - low) * fraction;
var App = React.createClass(
getInitialState: function()
return x: 0
,
move: function(i)
this.setState(x: this.state.x + i * 100);
,
render: function()
return <div className="ShowerItem">
<p>
<button onClick=this.move.bind(this, -1)>Left</button>
<button onClick=this.move.bind(this, 1)>Right</button>
</p>
<svg><Dot x=this.state.x/></svg>
</div>;
);
var Dot = React.createClass(
getInitialState: function()
return
x: 0,
final: 0
;
,
timer: null,
render: function()
var from = this.state.x;
var to = this.props.x;
if (to !== this.state.final)
this.state.final = to;
if (this.timer)
cancelAnimationFrame(this.timer.id);
this.timer = animate(500, function(fraction)
var x = lerp(from, to, fraction);
if (fraction >= 1)
this.setState(
value: to
);
this.timer = null;
else
this.setState(x: x);
.bind(this))
return <circle r="10" cy="10" cx=this.state.x + 10/>
);
React.renderComponent(
<App/>,
document.body
);
有没有更有效的制作动画的方法? 代码架构对吗?
CSS Transitions add-on 在这里没有帮助,因为我不使用 CSS。
【问题讨论】:
这个问题与 jQuery 无关,CSS 不会为提供的 SVG 示例做任何事情。 它在您计算机上的 Chrome 时间轴选项卡中的外观如何?对于我来说,一个典型的帧是:0.503 ms Scripting, 0.070 ms Rendering, 0.821 ms Painting, 0.782 ms Other, 14.007 ms Idle
,并且动画很流畅。
动画对我来说也很流畅。您可能还对通过 javascript 制作动画的 this demo(这是 Pete Hunt 在 29:30 在 JSConf.Asia talk "Rethinking Best Practices" 中展示的那个)感兴趣。
演示代码在github.com/petehunt/react-touch,但所有好东西都在github.com/petehunt/react-touch-lib。另一个你可能想看的是github.com/petehunt/react-raf-batching。
您可以查看github.com/aino/ainojs-animation,它提供了一个简单的动画界面和一个frame
回调,可用于设置状态。 README 中有一个简单的 React 示例。
【参考方案1】:
这是我目前想到的:http://jsfiddle.net/NV/NtP7n/。
我重写了 Dot
以利用 React 的绘制循环:
var Dot = React.createClass(
getInitialState: function()
return
start: 0,
x: 0,
final: 0,
startTime: 0
;
,
render: function()
var state = this.state;
var props = this.props;
var amount = 0;
if (state.final !== props.x)
state.final = props.x;
state.start = state.x;
state.startTime = Date.now();
else
amount = (Date.now() - state.startTime) / this.props.duration;
if (amount <= 1)
var x = state.start + amount * (props.x - state.start);
setTimeout(function()
this.setState(x: x);
.bind(this), 1);
else
state.final = state.x = x = props.x;
return <circle r="10" cy="10" cx=x + 10/>
);
我必须打电话:
setTimeout(function()
this.setState(current: x);
.bind(this), 1);
只是为了在下一个刻度上强制更新。我必须使用 setTimeout,因为 render
方法中不允许使用 setState。我想知道我是否可以在不使用 setTimeout 的情况下在下一个滴答时排队更新。
【讨论】:
您可能可以挂钩到 componentDidUpdate 以将下一个状态更改排队。我这样做不小心触发了无限的css转换循环:)【参考方案2】:我在我的 react-hammer 集成中成功使用了这个 project project 有一些锤子事件和反应动画的例子。
这里是动画“BlinkingThing”的代码:
var BlinkingThing = React.createClass(
mixins: [React.Animate],
blink: function ()
var that = this;
var animateAfter = function ()
that.animate(
color: 'green'
, that.props.blinkBack);
;
this.animate(
color: 'yellow'
, this.props.blinkTo, animateAfter);
,
componentDidReceiveProps: function ()
this.setState(color: this.props.color)
,
componentDidMount: function ()
this.setState(color: this.props.color)
,
receiveHammerEvent: function (ev)
if (ev)
var value = ev.type;
switch (value)
case 'tap':
this.blink();
break;
,
getInitialState: function ()
return ;
,
render: function ()
var style =
display: 'inline-block',
backgroundColor: this.state.color
;
return (<div style=style>this.props.children</div>);
);
您需要一些会传播副作用(例如触摸事件)的父组件来触发 BlinkingThing 组件中的状态更改(当您调用 this.animate func 时动画依赖于状态更改),我制作了一个 HitArea 组件来做那。它在发生时从传递锤子事件的子代中调用 receiveHammerEvent 函数。
【讨论】:
【参考方案3】:我自己也遇到了同样的问题,直到最近我才发现了 Rekapi。 该库提供基于状态的动画工具。查看教程https://github.com/jeremyckahn/rekapi/blob/master/docs/getting_started.md
诀窍是,上下文不必是画布或 DOM 元素,它可以是普通对象,即组件实例或 mixin,因此这为在你的 actor 中执行某些逻辑提供了可能性render 方法,然后在你的组件(上下文)上设置状态,或者简单地编写一个“一个技巧演员”,它总是将其状态转发给每一帧的组件。
【讨论】:
【参考方案4】:似乎react.animate 是一个积极维护且经常使用的 React 动画库。
(上面已经提到过,但是在所有链接中很容易错过)
注意:它带有/需要 underscore.js。
【讨论】:
以上是关于React.js:非 CSS 动画的主要内容,如果未能解决你的问题,请参考以下文章