反应组件之间的动画过渡
React animate transition between components
我想在两个组件之间设置动画,其中第一个组件淡出并从 DOM 中移除,然后下一个组件添加到 DOM 并淡入。否则,新组件添加到 DOM 并在删除旧组件之前占用 space。您可以在 fiddle:
中看到问题
http://jsfiddle.net/phepyezx/4
// css snippet
.switch-enter {
opacity: 0.01;
}
.switch-enter.switch-enter-active {
opacity: 1.0;
}
.switch-leave {
opacity: 1.0;
}
.switch-leave.switch-leave-active {
opacity: 0;
}
// React snippet
<ReactCSSTransitionGroup transitionName="switch">
<div key={key} className={className}>{this.text()}</div>
</ReactCSSTransitionGroup>
一个不可接受的解决方案(对我来说)是在转换到新组件之前用 css 隐藏原始组件,如下所示:
http://jsfiddle.net/phepyezx/5
// Change to css
.switch-leave {
visibility: hidden;
height: 0px;
width: 0px;
opacity: 1.0;
}
有没有办法 "delay" 在移除原始组件之前对安装新组件做出反应?我愿意使用 velocity 或其他一些库来实现这一点。
谢谢
另一种解决方案是使传入和传出元素占用相同的 space,例如让它们都绝对定位:
<ReactCSSTransitionGroup
className="container"
component="div"
transitionName="switch">
...
.container {
position: relative;
}
.container > div {
position: absolute;
}
http://jsfiddle.net/phepyezx/7/
可以用transition-delay
等离开成分消失再让进入成分出现,例如:
.fade-enter {
opacity: 0.01;
}
.fade-enter.fade-enter-active {
opacity: 1;
transition: opacity 1s;
transition-delay: 1s;
}
.fade-leave {
opacity: 1;
}
.fade-leave.fade-leave-active {
opacity: 0.01;
transition: opacity 1s;
}
使用 componentWillUnmount()
生命周期方法解决。
http://jsfiddle.net/phepyezx/9/
代码如下:
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
const Off = React.createClass({
componentWillUnmount () {
this.props.handleTransitionEnd();
},
render() {
return (
<div className="off button">OFF</div>
)
}
});
const On = React.createClass({
componentWillUnmount () {
this.props.handleTransitionEnd();
},
render() {
return (
<div className="on button">ON</div>
)
}
});
var Switch = React.createClass({
getInitialState: function() {
return {
on: false,
transitionEnd: true
};
},
toggle: function(e) {
this.setState({
on: !this.state.on,
transitionEnd: false
});
},
handleTransitionEnd() {
this.setState({transitionEnd: true});
},
renderOff() {
if (! this.state.on && this.state.transitionEnd) {
return (
<Off key="off" handleTransitionEnd={this.handleTransitionEnd} />
)
}
},
renderOn() {
if (this.state.on && this.state.transitionEnd) {
return (
<On key="on" handleTransitionEnd={this.handleTransitionEnd} />
)
}
},
render: function() {
return (
<div>
<button onClick={this.toggle}>Toggle</button>
<ReactCSSTransitionGroup transitionName="switch">
{this.renderOff()}
{this.renderOn()}
</ReactCSSTransitionGroup>
</div>
);
}
});
React.render(<Switch/>, document.getElementById("switch"));
以及相关的css:
.switch-enter {
opacity: 0.01;
}
.switch-enter.switch-enter-active {
opacity: 1.0;
transition: opacity 500ms ease-in;
}
.switch-leave {
opacity: 1.0;
}
.switch-leave.switch-leave-active {
opacity: 0;
transition: opacity 500ms ease-out;
}
您可以使用 实现相同的有效结果,它使用绝对定位和延迟而不是 componentWillUnmount()
如果你想延迟下一个组件的渲染,你可以使用这样的东西:
import React, { Component } from 'react';
export default class DelayedRender extends Component {
static propTypes = {
delay: React.PropTypes.number.isRequired,
children: React.PropTypes.element,
className: React.PropTypes.string
};
constructor(props) {
super(props);
this.state = {
render: false
};
}
componentDidMount() {
setTimeout(() => {
const delayedClassNames = this.refs.noDelayed.className;
this.setState({
render: true,
classNames: delayedClassNames
});
}, this.props.delay);
}
render() {
const { children, className } = this.props;
return this.state.render ?
<div className={this.state.classNames}>{children}</div> :
<div className={className} ref="noDelayed" ></div>;
}
}
并且在您的渲染方法中:
const ROUTE_TRANSITION_TIME = 500;
const views = [];
if (shouldRenderDelayedRoute) {
views.push(
<DelayedRender delay={ROUTE_TRANSITION_TIME} key="book">
<A ref="book"/>
</DelayedRender>
);
} else {
views.push(<B key="library"/>);
}
<ReactCSSTransitionGroup
transitionEnterTimeout={ROUTE_TRANSITION_TIME}
transitionLeaveTimeout={ROUTE_TRANSITION_TIME}
transitionName="fade-transition"
>
{views}
</ReactCSSTransitionGroup>
我想在两个组件之间设置动画,其中第一个组件淡出并从 DOM 中移除,然后下一个组件添加到 DOM 并淡入。否则,新组件添加到 DOM 并在删除旧组件之前占用 space。您可以在 fiddle:
中看到问题http://jsfiddle.net/phepyezx/4
// css snippet
.switch-enter {
opacity: 0.01;
}
.switch-enter.switch-enter-active {
opacity: 1.0;
}
.switch-leave {
opacity: 1.0;
}
.switch-leave.switch-leave-active {
opacity: 0;
}
// React snippet
<ReactCSSTransitionGroup transitionName="switch">
<div key={key} className={className}>{this.text()}</div>
</ReactCSSTransitionGroup>
一个不可接受的解决方案(对我来说)是在转换到新组件之前用 css 隐藏原始组件,如下所示:
http://jsfiddle.net/phepyezx/5
// Change to css
.switch-leave {
visibility: hidden;
height: 0px;
width: 0px;
opacity: 1.0;
}
有没有办法 "delay" 在移除原始组件之前对安装新组件做出反应?我愿意使用 velocity 或其他一些库来实现这一点。
谢谢
另一种解决方案是使传入和传出元素占用相同的 space,例如让它们都绝对定位:
<ReactCSSTransitionGroup
className="container"
component="div"
transitionName="switch">
...
.container {
position: relative;
}
.container > div {
position: absolute;
}
http://jsfiddle.net/phepyezx/7/
可以用transition-delay
等离开成分消失再让进入成分出现,例如:
.fade-enter {
opacity: 0.01;
}
.fade-enter.fade-enter-active {
opacity: 1;
transition: opacity 1s;
transition-delay: 1s;
}
.fade-leave {
opacity: 1;
}
.fade-leave.fade-leave-active {
opacity: 0.01;
transition: opacity 1s;
}
使用 componentWillUnmount()
生命周期方法解决。
http://jsfiddle.net/phepyezx/9/
代码如下:
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
const Off = React.createClass({
componentWillUnmount () {
this.props.handleTransitionEnd();
},
render() {
return (
<div className="off button">OFF</div>
)
}
});
const On = React.createClass({
componentWillUnmount () {
this.props.handleTransitionEnd();
},
render() {
return (
<div className="on button">ON</div>
)
}
});
var Switch = React.createClass({
getInitialState: function() {
return {
on: false,
transitionEnd: true
};
},
toggle: function(e) {
this.setState({
on: !this.state.on,
transitionEnd: false
});
},
handleTransitionEnd() {
this.setState({transitionEnd: true});
},
renderOff() {
if (! this.state.on && this.state.transitionEnd) {
return (
<Off key="off" handleTransitionEnd={this.handleTransitionEnd} />
)
}
},
renderOn() {
if (this.state.on && this.state.transitionEnd) {
return (
<On key="on" handleTransitionEnd={this.handleTransitionEnd} />
)
}
},
render: function() {
return (
<div>
<button onClick={this.toggle}>Toggle</button>
<ReactCSSTransitionGroup transitionName="switch">
{this.renderOff()}
{this.renderOn()}
</ReactCSSTransitionGroup>
</div>
);
}
});
React.render(<Switch/>, document.getElementById("switch"));
以及相关的css:
.switch-enter {
opacity: 0.01;
}
.switch-enter.switch-enter-active {
opacity: 1.0;
transition: opacity 500ms ease-in;
}
.switch-leave {
opacity: 1.0;
}
.switch-leave.switch-leave-active {
opacity: 0;
transition: opacity 500ms ease-out;
}
您可以使用 componentWillUnmount()
如果你想延迟下一个组件的渲染,你可以使用这样的东西:
import React, { Component } from 'react';
export default class DelayedRender extends Component {
static propTypes = {
delay: React.PropTypes.number.isRequired,
children: React.PropTypes.element,
className: React.PropTypes.string
};
constructor(props) {
super(props);
this.state = {
render: false
};
}
componentDidMount() {
setTimeout(() => {
const delayedClassNames = this.refs.noDelayed.className;
this.setState({
render: true,
classNames: delayedClassNames
});
}, this.props.delay);
}
render() {
const { children, className } = this.props;
return this.state.render ?
<div className={this.state.classNames}>{children}</div> :
<div className={className} ref="noDelayed" ></div>;
}
}
并且在您的渲染方法中:
const ROUTE_TRANSITION_TIME = 500;
const views = [];
if (shouldRenderDelayedRoute) {
views.push(
<DelayedRender delay={ROUTE_TRANSITION_TIME} key="book">
<A ref="book"/>
</DelayedRender>
);
} else {
views.push(<B key="library"/>);
}
<ReactCSSTransitionGroup
transitionEnterTimeout={ROUTE_TRANSITION_TIME}
transitionLeaveTimeout={ROUTE_TRANSITION_TIME}
transitionName="fade-transition"
>
{views}
</ReactCSSTransitionGroup>