use*_*767 2 javascript animation reactjs
我遇到了复杂动画的问题,其中一个组件必须在另一个组件之前完成动画.在这个例子中,我试图在另一个组件淡入之前淡出组件.我不能使用react-motion或任何第三方库,也不能依赖css转换.这是一个突出问题的工作示例.请注意,"编辑器"和"显示"组件的高度并不总是相同.
使用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({
componentWillEnter: function(callback) {
var container = $(React.findDOMNode(this.refs.fade));
container.animate({
opacity:1
}, callback);
},
componentWillLeave: 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')
);
Run Code Online (Sandbox Code Playgroud)
CSS
.row {
background-color: #c9c9c9;
border-bottom: 1px solid #dedede;
padding: 5px;
color: gray;
cursor:pointer;
}
Run Code Online (Sandbox Code Playgroud)
HTML
<script src="https://ajax.googleapis.com/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>
Run Code Online (Sandbox Code Playgroud)
真的,像React Motion这样的东西就是答案,因为它实现了你想要的功能.但是,它自然可以实现它.我将概述我创建的类似效果,演示了一些技术,然后将其应用到最后的特定代码中.
我实现的效果(一次一个地淡入或淡出儿童)是通过使用几个组件创建的:
StaggerIn- 一个让孩子一个接一个地逐渐消失的组件,将动画错开props.delay几毫秒.这个组件实现了一个TransitionGroup并将子包装在一个StaggeringChild.StaggeringChild- 实现React TransitionGroup回调以执行实际动画的组件.渲染时,将子项包装在StaggerIn组件中会触发效果:
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} />;
}
Run Code Online (Sandbox Code Playgroud)
为了做出惊人的工作,StaggerIn 计算孩子的数量,并通过确定每个孩子的指数(乘以delay值)来确定适当的延迟:
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>
);
}
});
Run Code Online (Sandbox Code Playgroud)
如上所述,StaggerChild实际上是动画; 在这里我使用了TweenLite动画库中_animateIn和_animateOut,但jQuery的动画等应罚款以及工作:
var StaggeringChild = React.createClass({
getDefaultProps: function() {
return {
tag: "div"
};
},
componentWillAppear: function(callback) {
this._animateIn(callback);
},
componentWillEnter: function(callback) {
this._animateIn(callback);
},
componentWillLeave: 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>;
}
});
Run Code Online (Sandbox Code Playgroud)
这是一个显示完成效果的JSFiddle:http://jsfiddle.net/BinaryMuse/s2z0vmcn/
完成所有这些工作的关键是在开始设置动画之前计算适当的超时值.在你的情况下,它很容易:你知道你有两个动画项目,你总是希望淡出一个离开之前你淡入一个出现.
首先,让我们为一个新的prop指定一个默认属性time,它将指定动画应该花多长时间(因为我们需要知道等待多长时间):
var Fade = React.createClass({
getDefaultProps: function() {
return { time: 400 };
},
// ...
});
Run Code Online (Sandbox Code Playgroud)
接下来,我们将修改动画方法,以便立即离开,但出现等待this.props.time毫秒,以便离开有时间先完成.
var Fade = React.createClass({
// ...
// no change to this function
componentWillLeave: function(callback) {
var container = $(React.findDOMNode(this.refs.fade));
container.animate({
opacity:0
}, this.props.time, callback);
},
componentWillEnter: 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);
},
// ...
});
Run Code Online (Sandbox Code Playgroud)
通过这些更改,正在消失的项目将在出现动画的项目之前生成动画.由于DOM的工作方式(交叉渐变元素非常困难)会有一些跳跃,这将留给读者作为练习.:)
这是一个有效的JSFiddle,其中包含完整的代码:https://jsfiddle.net/BinaryMuse/xfz3seyc/
| 归档时间: |
|
| 查看次数: |
2628 次 |
| 最近记录: |