这么简单的事情应该很容易完成,但我却对它的复杂程度感到抓狂。
我想做的就是为 React 组件的安装和卸载设置动画,仅此而已。以下是我迄今为止尝试过的方法以及每个解决方案不起作用的原因:
-
ReactCSSTransitionGroup
- 我根本没有使用 CSS 类,它都是 JS 样式,所以这不起作用。
-
ReactTransitionGroup
- 这个较低级别的 API 很棒,但它要求您在动画完成时使用回调,因此仅使用 CSS 过渡在这里不起作用。动画库总是有的,这就引出了下一点:
- GreenSock - 在我看来,许可对于商业用途来说过于严格。
- React Motion - 这看起来很棒,但是
TransitionMotion
对于我的需要来说非常混乱且过于复杂。
- 当然,我可以像 Material UI 那样做一些欺骗,其中元素被渲染但保持隐藏(
left: -10000px
)但我宁愿不走那条路。我认为它很hacky,而且我want我的组件要卸载,这样它们就会清理干净并且不会弄乱 DOM。
我想要的东西是easy来实施。在安装时,为一组样式设置动画;卸载时,为相同(或另一组)样式设置动画。完毕。它还必须在多个平台上具有高性能。
我在这里碰壁了。如果我遗漏了什么并且有一个简单的方法可以做到这一点,请告诉我。
这有点长,但我已经使用了所有本机事件和方法来实现此动画。不ReactCSSTransitionGroup
, ReactTransitionGroup
等等。
我用过的东西
- React 生命周期方法
-
onTransitionEnd
event
这是如何运作的
- 根据传递的 mount 属性安装元素(
mounted
) 并使用默认样式(opacity: 0
)
- 挂载或更新后,使用
componentDidMount
(componentWillReceiveProps
进一步更新)更改样式(opacity: 1
)并设置超时(以使其异步)。
- 卸载时,向组件传递一个 prop 来标识卸载,再次更改样式(
opacity: 0
), onTransitionEnd
,从 DOM 中删除卸载元素。
继续循环。
看看代码你就明白了。如果需要任何澄清,请发表评论。
class App extends React.Component{
constructor(props) {
super(props)
this.transitionEnd = this.transitionEnd.bind(this)
this.mountStyle = this.mountStyle.bind(this)
this.unMountStyle = this.unMountStyle.bind(this)
this.state ={ //base css
show: true,
style :{
fontSize: 60,
opacity: 0,
transition: 'all 2s ease',
}
}
}
componentWillReceiveProps(newProps) { // check for the mounted props
if(!newProps.mounted)
return this.unMountStyle() // call outro animation when mounted prop is false
this.setState({ // remount the node when the mounted prop is true
show: true
})
setTimeout(this.mountStyle, 10) // call the into animation
}
unMountStyle() { // css for unmount animation
this.setState({
style: {
fontSize: 60,
opacity: 0,
transition: 'all 1s ease',
}
})
}
mountStyle() { // css for mount animation
this.setState({
style: {
fontSize: 60,
opacity: 1,
transition: 'all 1s ease',
}
})
}
componentDidMount(){
setTimeout(this.mountStyle, 10) // call the into animation
}
transitionEnd(){
if(!this.props.mounted){ // remove the node on transition end when the mounted prop is false
this.setState({
show: false
})
}
}
render() {
return this.state.show && <h1 style={this.state.style} onTransitionEnd={this.transitionEnd}>Hello</h1>
}
}
class Parent extends React.Component{
constructor(props){
super(props)
this.buttonClick = this.buttonClick.bind(this)
this.state = {
showChild: true,
}
}
buttonClick(){
this.setState({
showChild: !this.state.showChild
})
}
render(){
return <div>
<App onTransitionEnd={this.transitionEnd} mounted={this.state.showChild}/>
<button onClick={this.buttonClick}>{this.state.showChild ? 'Unmount': 'Mount'}</button>
</div>
}
}
ReactDOM.render(<Parent />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-with-addons.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)