目标:为react组件轻松的添加动画效果。
<Transition
in={ flag } // 控制动画展示的变量
timeout={ 300 } // 动画持续时间
animation='zoom-in-top‘
>
{ node }
</Transition>
拿导航栏的鼠标移入效果举例:
鼠标移入时,下拉框展示,箭头向上旋转180;鼠标移出时,箭头向下旋转180,然后弹出层消失。
解决方案: 记录一个状态,当鼠标点击时,给这个元素添加一个类名,再次点击时,取消这个类名。
现在添加css效果,一开始的时候,ul是不展示的,即不显示在页面中。让元素不显示在页面中有两种方法:
- 元素存在于页面,但是看不见,使用opacity属性,设置为0
- 使用display:none,让元素不存在于页面。
这里初始的时候,显然只能使用第二种,因为第一种容易发生误点的情况。
但是这种情况存在一个问题,就是当组件再次点击消失的时候,display属性设置为none之后,其动画效果失效了,所以会导致在再次点击关闭的时候没有动画效果。
所以此时,我们引入第三方的动画插件库,来帮助我们解决这个问题.
- 快速上手使用CSSTransition
yarn add react-transition-group
yarn add @types/react-transition-group
import { CSSTransitionGroup } from 'react-transition-group'
<CSSTransition
in={inProp}
timeout={200}
classNames="my-node”
>
<div>
hello world
</div>
</CSSTransition>
然后在样式组件上写入:
.my-node-enter {
opacity: 0;
}
.my-node-enter-active {
opacity: 1;
transition: opacity 200ms;
}
.my-node-exit {
opacity: 1;
}
.my-node-exit-active {
opacity: 0;
transition: opacity 200ms;
}
这样就给hello world元素添加上了一个简单动画。
2. 使用CSSTransition解决刚才的问题
因为该组件库有一个属性,unmountOnExit,即当in属性变化时,如果变为true,则会在当前页面渲染出内部元素,当为false时,会自动删除其中的节点。
所以我们将该属性附上,并添加一个appear属性,当初始化时动画也生效
<CSSTransition
in={inProp}
timeout={200}
classNames="my-node”
unmountOnExit
appear
>
<div>
hello world
</div>
</CSSTransition>
3. 接下来,我们对于该组件做一次类似Icon组件的二次封装,将通用的属性设置为默认属性,并提供一些常用的动画效果
import React from 'react'
import { CSSTransition } from 'react-transition-group'
import { CSSTransitionProps } from 'react-transition-group/CSSTransition'
type TAnimationName = 'zoom-in-top' | 'zoom-in-left'
type TransitionProps = CSSTransitionProps & {
animation?: TAnimationName,
wrapper? : boolean,
}
const Transition: React.FC<TransitionProps> = (props) => {
const { children, classNames, animation, wrapper, ...restProps } = props
console.log('classNames', classNames);
console.log('animation', animation);
return (
<CSSTransition
classNames={classNames ? classNames : animation}
{...restProps}
>
{ children }
</CSSTransition>
)
}
Transition.defaultProps = {
unmountOnExit: true,
appear: true,
}
export default Transition
这样我们就能够使用方便的动画效果:
<Transition
in={ flag } // 控制动画展示的变量
timeout={ 300 } // 动画持续时间
animation='zoom-in-top‘
>
{ node }
</Transition>