admin管理员组文章数量:1398984
I'm having problems with plex animations, where one ponent has to finish animating before another. In this example, I'm trying to fade out a ponent before another ponent is faded in. I can't use react-motion or any third party library, and can't rely on css transitions. Here is a working example highlighting the problem. Please note that the 'Editor' and 'Display' ponents aren't always of the same height.
Javascript
var Editor = React.createClass({
render: function() {
return <input type="text" defaultValue={this.props.name} />
}
});
var Display = React.createClass({
render: function() {
return <div>{this.props.name}</div>;
}
});
var Row = React.createClass({
getInitialState: function() {
return {
isEditing: false
}
},
updateRow: function() {
this.setState({isEditing: !this.state.isEditing});
},
render: function() {
return (
<div className="row" onClick={this.updateRow}>
<React.addons.TransitionGroup>
{
this.state.isEditing ?
<Fade key="e"><Editor name={this.props.name}/></Fade> :
<Fade key="d"><Display name={this.props.name}/></Fade>
}
</React.addons.TransitionGroup>
</div>);
}
});
var Table = React.createClass({
render: function() {
return (
<div className="row" onClick={this.updateRow}>
<Row name="One" />
<Row name="Two" />
<Row name="Three" />
<Row name="Four" />
</div>);
}
});
var Fade = React.createClass({
ponentWillEnter: function(callback) {
var container = $(React.findDOMNode(this.refs.fade));
container.animate({
opacity:1
}, callback);
},
ponentWillLeave: function(callback) {
var container = $(React.findDOMNode(this.refs.fade));
container.animate({
opacity:0
}, callback);
},
render: function() {
return(<div className="fade" ref="fade">
{this.props.children}
</div>)
}
});
ReactDOM.render(
<Table />,
document.getElementById('container')
);
CSS
.row {
background-color: #c9c9c9;
border-bottom: 1px solid #dedede;
padding: 5px;
color: gray;
cursor:pointer;
}
HTML
<script src=".11.1/jquery.min.js"></script>
<script src=".js">
</script>
<div id="container">
</div>
I'm having problems with plex animations, where one ponent has to finish animating before another. In this example, I'm trying to fade out a ponent before another ponent is faded in. I can't use react-motion or any third party library, and can't rely on css transitions. Here is a working example highlighting the problem. Please note that the 'Editor' and 'Display' ponents aren't always of the same height.
Javascript
var Editor = React.createClass({
render: function() {
return <input type="text" defaultValue={this.props.name} />
}
});
var Display = React.createClass({
render: function() {
return <div>{this.props.name}</div>;
}
});
var Row = React.createClass({
getInitialState: function() {
return {
isEditing: false
}
},
updateRow: function() {
this.setState({isEditing: !this.state.isEditing});
},
render: function() {
return (
<div className="row" onClick={this.updateRow}>
<React.addons.TransitionGroup>
{
this.state.isEditing ?
<Fade key="e"><Editor name={this.props.name}/></Fade> :
<Fade key="d"><Display name={this.props.name}/></Fade>
}
</React.addons.TransitionGroup>
</div>);
}
});
var Table = React.createClass({
render: function() {
return (
<div className="row" onClick={this.updateRow}>
<Row name="One" />
<Row name="Two" />
<Row name="Three" />
<Row name="Four" />
</div>);
}
});
var Fade = React.createClass({
ponentWillEnter: function(callback) {
var container = $(React.findDOMNode(this.refs.fade));
container.animate({
opacity:1
}, callback);
},
ponentWillLeave: function(callback) {
var container = $(React.findDOMNode(this.refs.fade));
container.animate({
opacity:0
}, callback);
},
render: function() {
return(<div className="fade" ref="fade">
{this.props.children}
</div>)
}
});
ReactDOM.render(
<Table />,
document.getElementById('container')
);
CSS
.row {
background-color: #c9c9c9;
border-bottom: 1px solid #dedede;
padding: 5px;
color: gray;
cursor:pointer;
}
HTML
<script src="https://ajax.googleapis./ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://facebook.github.io/react/js/jsfiddle-integration-babel.js">
</script>
<div id="container">
</div>
Share
Improve this question
edited Dec 12, 2015 at 8:01
user1036767
asked Dec 12, 2015 at 7:43
user1036767user1036767
271 silver badge7 bronze badges
1 Answer
Reset to default 8Really, something like React Motion is the answer here, because it implements the functionality you want. However, it's certainly possible to implement it yourself. I'll overview a similar effect I created that demonstrates some techniques, then apply it to your specific code at the end.
The effect I implemented (fading children in or out one-at-a-time) was created by using a couple ponents:
StaggerIn
- a ponent that fades its children in or out one-by-one, staggering the animations byprops.delay
milliseconds. This ponent is implemented with aTransitionGroup
and wrapping the children in aStaggeringChild
.StaggeringChild
- a ponent that implements React'sTransitionGroup
callbacks to do the actual animation.
When rendering, wrapping the children in a StaggerIn
ponent triggers the effect:
if (this.state.active) {
return (
<StaggerIn delay={100}>
<div key="one">One</div>
<div key="two">Two</div>
<div key="three">Three</div>
<div key="four">Four</div>
<div key="five">Five</div>
<div key="six">Six</div>
<div key="seven">Seven</div>
</StaggerIn>
);
} else {
return <StaggerIn delay={100} />;
}
To make the staggering work, StaggerIn
counts the number of children, and determines the appropriate delay by determining the index of each child (multiplied by the delay
value):
var StaggerIn = React.createClass({
render: function() {
var childCount = React.Children.count(this.props.children);
var children = React.Children.map(this.props.children, function(child, idx) {
var inDelay = this.props.delay * idx;
var outDelay = this.props.delay * (childCount - idx - 1);
return (
<StaggeringChild key={child.key}
animateInDelay={inDelay}
animateOutDelay={outDelay}>
{child}
</StaggeringChild>
);
}.bind(this));
return (
<React.addons.TransitionGroup>
{children}
</React.addons.TransitionGroup>
);
}
});
As mentioned, StaggerChild
actually does the animation; here I'm using the TweenLite
animation library in _animateIn
and _animateOut
, but jQuery animations and the like should work fine as well:
var StaggeringChild = React.createClass({
getDefaultProps: function() {
return {
tag: "div"
};
},
ponentWillAppear: function(callback) {
this._animateIn(callback);
},
ponentWillEnter: function(callback) {
this._animateIn(callback);
},
ponentWillLeave: function(callback) {
this._animateOut(callback);
},
_animateIn(callback) {
var el = React.findDOMNode(this);
TweenLite.set(el, {opacity: 0});
setTimeout(function() {
console.log("timed in");
TweenLite.to(el, 1, {opacity: 1}).play().eventCallback("onComplete", callback);
}, this.props.animateInDelay);
},
_animateOut(callback) {
var el = React.findDOMNode(this);
setTimeout(function() {
TweenLite.to(el, 1, {opacity: 0}).play().eventCallback("onComplete", callback);
}, this.props.animateOutDelay);
},
render: function() {
var Comp = this.props.tag;
var { tag, animateInDelay, animateOutDelay, ...props } = this.props;
return <Comp {...props}>{this.props.children}</Comp>;
}
});
Here's a JSFiddle showing the pleted effect: http://jsfiddle/BinaryMuse/s2z0vmcn/
The key to making all this work is calculating the appropriate timeout value before you start to animate in or out. In your case, it's easy: you know you have exactly two items to animate, and you always want to fade out the one leaving before you fade in the one appearing.
First, let's specify a default property for a new prop called time
that will specify how long the animation should take (since we'll need to know how long to wait):
var Fade = React.createClass({
getDefaultProps: function() {
return { time: 400 };
},
// ...
});
Next, we'll modify the animation methods so that leaving happens immediately, but appearing waits this.props.time
milliseconds so that the leaving has time to finish first.
var Fade = React.createClass({
// ...
// no change to this function
ponentWillLeave: function(callback) {
var container = $(React.findDOMNode(this.refs.fade));
container.animate({
opacity:0
}, this.props.time, callback);
},
ponentWillEnter: function(callback) {
var container = $(React.findDOMNode(this.refs.fade));
// hide element immediately
container.css({opacity: 0});
// wait until the leave animations finish before fading in
setTimeout(function() {
container.animate({
opacity:1
}, this.props.time, callback);
}.bind(this), this.props.time);
},
// ...
});
With those changes, the item that's disappearing will animate out before the item that's appearing animates in. There's a bit of jumpiness because of the way the DOM works (crossfading elements is notoriously difficult) that will be left as an exercise to the reader. :)
Here's a working JSFiddle with the pleted code: https://jsfiddle/BinaryMuse/xfz3seyc/
本文标签: javascriptHow to sequence animations in ReactJsStack Overflow
版权声明:本文标题:javascript - How to sequence animations in ReactJs - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744205285a2595156.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论