javascript React.js:非 CSS 动画
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/23906603/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
React.js: Non-CSS animations
提问by NVI
React documentationdoesn't have anything about handling animations that are not CSS transitions, such as animation of scroll position and SVG attributes.
React 文档没有任何关于处理非 CSS 转换动画的内容,例如滚动位置和 SVG 属性的动画。
As for CSS transitions, there is an add-on.
至于 CSS 过渡,有一个附加组件。
Here is 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
);
Is there a more efficient way of doing animations?
It the code architecture right?
有没有更有效的动画制作方法?
它的代码架构对吗?
CSS Transitions add-ondoesn't help here since I don't use CSS.
CSS Transitions 插件在这里没有帮助,因为我不使用 CSS。
回答by Sergey Lapin
I successfully used this projectin my react-hammer integration projectthere are some examples with hammer events and react animation.
我在我的 react-hammer 集成项目中成功地使用了这个项目,有一些关于锤子事件和反应动画的例子。
Here code of animated "BlinkingThing":
这是动画“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>);
}
});
You need some parent component which will propagate side effects(touch events, for example) to trigger changes of state in BlinkingThing component (animation rely on state changing when you call this.animate func), I made a HitArea component to do that. It calls receiveHammerEvent func from its children passing hammer event when it occurs.
您需要一些父组件来传播副作用(例如触摸事件)以触发 BlinkingThing 组件中的状态更改(动画依赖于调用 this.animate func 时的状态更改),我制作了一个 HitArea 组件来做到这一点。当它发生时,它从传递锤子事件的子级调用receiveHammerEvent func。
回答by user3089094
Been having the same exact problems myself, until recently I've found out about Rekapi. This library provides state-based animations tools. Check out the tutorial https://github.com/jeremyckahn/rekapi/blob/master/docs/getting_started.md
我自己也遇到过同样的问题,直到最近我才发现了 Rekapi。该库提供基于状态的动画工具。查看教程https://github.com/jeremyckahn/rekapi/blob/master/docs/getting_started.md
The trick is, the context doesn't have to be a canvas or a DOM element, it can be a plain object, i.e. a component instance or a mixin, so this opens the possibility either to perform some logic in your actor's render method and then setState on your component(context), or simply write a "one trick actor" that always forwards its state to the component each frame.
诀窍是,上下文不必是画布或 DOM 元素,它可以是一个普通对象,即组件实例或 mixin,因此这开启了在您的演员的渲染方法中执行某些逻辑和然后在您的组件(上下文)上设置状态,或者简单地编写一个“一个特技演员”,它总是在每一帧将其状态转发给组件。
回答by Flion
It seems react.animateis an actively maintained and often used React animation libraries.
看起来react.animate是一个积极维护且经常使用的 React 动画库。
(it was already mentioned above, but would be easy to miss in all the links)
(上面已经提到过,但在所有链接中很容易错过)
Note: it comes with/requires underscore.js.
注意:它带有/需要 underscore.js。
回答by NVI
This is what I came up so far: http://jsfiddle.net/NV/NtP7n/.
这是我到目前为止想到的:http: //jsfiddle.net/NV/NtP7n/。
I rewrote Dot
to leverage React's draw loop:
我重写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}/>
}
});
I have to call:
我必须打电话:
setTimeout(function() {
this.setState({current: x});
}.bind(this), 1);
just to force update on the next tick. I have to use setTimeout because setState isn't allowed in render
method. I wonder if I can queue an update on the next tick without using setTimeout.
只是为了在下一个刻度上强制更新。我必须使用 setTimeout 因为 setState 在render
方法中是不允许的。我想知道是否可以在不使用 setTimeout 的情况下在下一个滴答声中排队更新。