有些组件需要一些简单的淡入淡出css动画效果 通过visible为触发点 主要就是在visible切换true/false的时候做出简单动画 enter类型和appear类型不让一起出现
CSS animation 与 CSS transition 有何区别?
https://www.zhihu.com/question/19749045
Transition 强调过渡,Transition + Transform = 两个关键帧的Animation
Animation 强调流程与控制,Duration + TransformLib + Control = 多个关键帧的Animation
如果只有两个关键帧我会选择Transition + Transform
[
](https://ant.design/components/alert-cn/)
rc-motion做的事情
实际功能例子
https://ant.design/components/alert-cn/
在css中已经预先写好各个动画的类名和动画名
// relative path
components/alert/style/index.less
// transition.transition {transition: background 0.3s, height 1.3s, opacity 1.3s;// transition: all 5s!important;&.transition-appear,&.transition-enter {opacity: 0;}...}// animation.animation {animation-duration: 1.3s;animation-fill-mode: both;&.animation-appear,&.animation-enter {animation-name: enter;animation-fill-mode: both;animation-play-state: paused;}...}// keyframes@keyframes enter {from {transform: scale(0);opacity: 0;}to {transform: scale(1);opacity: 1;}}
通过控制status来获取对应钩子,可产生对应的样式或者执行用户自定义操作,控制类名添加和删除
用户各个阶段传入的钩子
// 动画状态export const STATUS_NONE = 'none' as const;export const STATUS_APPEAR = 'appear' as const;export const STATUS_ENTER = 'enter' as const;export const STATUS_LEAVE = 'leave' as const;// visible变化 判断属于哪个statususeIsomorphicLayoutEffect(() => {let nextStatus: MotionStatus;if (!isMounted && visible && motionAppear) {nextStatus = STATUS_APPEAR;}if (isMounted && visible && motionEnter) {nextStatus = STATUS_ENTER;}if ((isMounted && !visible && motionLeave) ||(!isMounted && motionLeaveImmediately && !visible && motionLeave)) {nextStatus = STATUS_LEAVE;}if (nextStatus) {setStatus(nextStatus);startStep();}}, [visible]);// 通过status匹配钩子const eventHandlers = React.useMemo<{[STEP_PREPARE]?: MotionPrepareEventHandler;[STEP_START]?: MotionEventHandler;[STEP_ACTIVE]?: MotionEventHandler;}>(() => {switch (status) {case STATUS_APPEAR:return {[STEP_PREPARE]: onAppearPrepare,[STEP_START]: onAppearStart,[STEP_ACTIVE]: onAppearActive,};case STATUS_ENTER:return {[STEP_PREPARE]: onEnterPrepare,[STEP_START]: onEnterStart,[STEP_ACTIVE]: onEnterActive,};case STATUS_LEAVE:return {[STEP_PREPARE]: onLeavePrepare,[STEP_START]: onLeaveStart,[STEP_ACTIVE]: onLeaveActive,};default:return {};}}, [status]);// 传入钩子返回值可作为最新样式onLeaveActive={() => { background: 'green' }}
step控制请求浏览器下一帧空闲执行动画且更新需要的动态样式
if (eventHandlers[STEP_PREPARE] && step === STEP_START) {mergedStyle = {transition: 'none',...mergedStyle,};}
useDomMotionEvents
绑定和解绑动画结束事件
一般都是用户只关心动画什么时候结束
为什么不用监听开始?
// 动画名称 需要考虑兼容性animationend | transitionend// 绑定和解绑addEventListenerremoveEventListener
motion
// 构建浏览器动画样式前缀 兼容性 作为事件监听名称的兼容prefixes[styleProp.toLowerCase()] = eventName.toLowerCase();prefixes[`Webkit${styleProp}`] = `webkit${eventName}`;prefixes[`Moz${styleProp}`] = `moz${eventName}`;prefixes[`ms${styleProp}`] = `MS${eventName}`;prefixes[`O${styleProp}`] = `o${eventName.toLowerCase()}`;// 组合两个关键字animationend | transitionend
