React 管理动画播放时间主要通过 SCSS 变更 className 实现。
比如,原本 className 为${styles.cssClassA}
,当 className 变为${styles.cssClassA} ${styles.ani1}
时,会将 style.ani1
里的样式加入到 style.cssClassA
中,如果style.ani1
里碰巧有animation: aniName ....
这样的样式,自然动画效果就在此时开始执行了。
在 scss 文件中的写法是这样的
@keyframes aniName {
0% {
transform: translate3d(0px, 0, 0);
}
100% {
transform: translate3d(1000px, 0, 0);
}
}
div.cssClassA {
&.ani1 {
animation: aniName 1s linear forwards 0s;
/* 动画名,播放时间,线性变化,保持动画最后的状态,延迟0秒开始播放 */
}
}
这种方式虽然好用,却有许多的坑,需要着重避开。
如果要在特定的时间触发动画,就免不了在 render 阶段修改 className 的值。而这个值通常被 ref 的值所影响。在这个过程中,比较容易出问题的点,是在使用完 ref 的值后立即修改它。
我遇到的问题是,在 render 阶段,用完 ref(boolean) 的值后将其立即将其取反,比如初始值为 false,改为 true。下次取该 ref 值的时候却没有发生变化(仍为 false),好像从未修改一样。打 log 输出 ref 的值,可以证明确实有修改。最奇怪的是,同样可以通过 log 说明这种修改只执行了一次
引用:
https://segmentfault.com/a/1190000024536290
在异步渲染里 render 阶段可能会多次执行。
为什么多次执行但是却没有多次 log 呢?这个之后再研究吧,只能说有些前辈也遇到过同样的问题。
正确的做法是在事件响应阶段修改 ref,一般要播放动画的场景都是先有一个事件,然后那个事件的结果是要进行动画的播放吧。
当然,不能修改 ref,更不能修改 state。state 刷新 -> rerender -> state 刷新 -> rerender,死循环了
我听说过,如果动画前后,className 没有修改,那么不会生效的情况。比如有一个 fadeout 的动画,上次播放的时候停在消失到最后的场景,之后再让它 fadeout,却不出现了。这就是因为 className 一直都是${style.A} ${style.fadeout}
,没有触发 dom 的更新。
但是定义两个 className,让它们类名不同动画效果相同,二者相互切换,却仍然不生效。
尝试修改播放时间或 animationDelay 的值,没有效果
解决方案是写两个 animationName,其中包含细微的区别,比如一个是 0%什么什么->100%什么什么,变成 0%什么什么->99%什么什么->100%什么什么。99% 和 100%的效果可以是一样的。这样进行切换就好了