我遇到了复杂动画的问题,其中一个组件必须在另一个组件之前完成动画.在这个例子中,我试图在另一个组件淡入之前淡出组件.我不能使用react-motion或任何第三方库,也不能依赖css转换.这是一个突出问题的工作示例.请注意,"编辑器"和"显示"组件的高度并不总是相同.
使用Javascript
var Editor = React.createClass({ render: function() { return } }); var Display = React.createClass({ render: function() { return{this.props.name}; } }); var Row = React.createClass({ getInitialState: function() { return { isEditing: false } }, updateRow: function() { this.setState({isEditing: !this.state.isEditing}); }, render: function() { return (); } }); var Table = React.createClass({ render: function() { return ({ this.state.isEditing ? : } ); } }); 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(|
|
|
{this.props.children}) } }); ReactDOM.render(
CSS
.row { background-color: #c9c9c9; border-bottom: 1px solid #dedede; padding: 5px; color: gray; cursor:pointer; }
HTML
Michelle Til.. 7
真的,像React Motion这样的东西就是答案,因为它实现了你想要的功能.但是,它自然可以实现它.我将概述我创建的类似效果,演示了一些技术,然后将其应用到最后的特定代码中.
我实现的效果(一次一个地淡入或淡出儿童)是通过使用几个组件创建的:
StaggerIn
- 一个让孩子一个接一个地逐渐消失的组件,将动画错开props.delay
几毫秒.这个组件实现了一个TransitionGroup
并将子包装在一个StaggeringChild
.
StaggeringChild
- 实现React TransitionGroup
回调以执行实际动画的组件.
渲染时,将子项包装在StaggerIn
组件中会触发效果:
if (this.state.active) { return (); } else { return OneTwoThreeFourFiveSixSeven; }
为了做出惊人的工作,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 ({child} ); }.bind(this)); return ({children} ); } });
如上所述,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{this.props.children} ; } });
这是一个显示完成效果的JSFiddle:http://jsfiddle.net/BinaryMuse/s2z0vmcn/
完成所有这些工作的关键是在开始设置动画之前计算适当的超时值.在你的情况下,它很容易:你知道你有两个动画项目,你总是希望淡出一个离开之前你淡入一个出现.
首先,让我们为一个新的prop指定一个默认属性time
,它将指定动画应该花多长时间(因为我们需要知道等待多长时间):
var Fade = React.createClass({ getDefaultProps: function() { return { time: 400 }; }, // ... });
接下来,我们将修改动画方法,以便立即离开,但出现等待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); }, // ... });
通过这些更改,正在消失的项目将在出现动画的项目之前生成动画.由于DOM的工作方式(交叉渐变元素非常困难)会有一些跳跃,这将留给读者作为练习.:)
这是一个有效的JSFiddle,其中包含完整的代码:https://jsfiddle.net/BinaryMuse/xfz3seyc/
真的,像React Motion这样的东西就是答案,因为它实现了你想要的功能.但是,它自然可以实现它.我将概述我创建的类似效果,演示了一些技术,然后将其应用到最后的特定代码中.
我实现的效果(一次一个地淡入或淡出儿童)是通过使用几个组件创建的:
StaggerIn
- 一个让孩子一个接一个地逐渐消失的组件,将动画错开props.delay
几毫秒.这个组件实现了一个TransitionGroup
并将子包装在一个StaggeringChild
.
StaggeringChild
- 实现React TransitionGroup
回调以执行实际动画的组件.
渲染时,将子项包装在StaggerIn
组件中会触发效果:
if (this.state.active) { return (); } else { return OneTwoThreeFourFiveSixSeven; }
为了做出惊人的工作,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 ({child} ); }.bind(this)); return ({children} ); } });
如上所述,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{this.props.children} ; } });
这是一个显示完成效果的JSFiddle:http://jsfiddle.net/BinaryMuse/s2z0vmcn/
完成所有这些工作的关键是在开始设置动画之前计算适当的超时值.在你的情况下,它很容易:你知道你有两个动画项目,你总是希望淡出一个离开之前你淡入一个出现.
首先,让我们为一个新的prop指定一个默认属性time
,它将指定动画应该花多长时间(因为我们需要知道等待多长时间):
var Fade = React.createClass({ getDefaultProps: function() { return { time: 400 }; }, // ... });
接下来,我们将修改动画方法,以便立即离开,但出现等待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); }, // ... });
通过这些更改,正在消失的项目将在出现动画的项目之前生成动画.由于DOM的工作方式(交叉渐变元素非常困难)会有一些跳跃,这将留给读者作为练习.:)
这是一个有效的JSFiddle,其中包含完整的代码:https://jsfiddle.net/BinaryMuse/xfz3seyc/