Подтвердить что ты не робот

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.

4b9b3361

Ответ 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.