React.js: анимация без CSS
Реагировать на документацию не имеет ничего об обработке анимаций, которые не являются переходами CSS, такими как анимация положения прокрутки и атрибутов SVG.
Что касается переходов CSS, то надстройка.
Вот простой пример примера SVG:
![Animated SVG circle]()
/**
* @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 не помогает здесь, так как я не использую CSS.
Ответы
Ответ 1
Я успешно использовал этот проект в моей интеграции с интерактивным молотом 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 от своих дочерних элементов, проходящих через молот, когда это происходит.
Ответ 2
У меня были одни и те же проблемы, до недавнего времени я узнал о Рекапи.
Эта библиотека предоставляет средства анимации на основе состояния. Посмотрите учебник https://github.com/jeremyckahn/rekapi/blob/master/docs/getting_started.md
Фокус в том, что контекст не должен быть холстом или элементом DOM, он может быть простым объектом, то есть экземпляром компонента или микшированием, поэтому это открывает возможность либо выполнить некоторую логику в вашем акторе метод render, а затем setState на вашем компоненте (контексте) или просто напишите "один трюк-актер", который всегда пересылает свое состояние компоненту в каждый кадр.
Ответ 3
Кажется, react.animate - это активно поддерживаемые и часто используемые библиотеки анимации React.
(это уже упоминалось выше, но было бы легко пропустить во всех ссылках)
Примечание: он поставляется с/требует underscore.js.
Ответ 4
Это то, к чему я пришел: http://jsfiddle.net/NV/NtP7n/.
Я переписал Dot
, чтобы использовать цикл Reacts draw:
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, потому что setState не разрешен в методе render
. Интересно, могу ли я поставить очередь на обновление следующего тика без использования setTimeout.