javascript - 在进入时动画无法工作(Tailwind、TransitionGroup、Typescript)
我创建了一个包装组件,通过字符串提供类名列表,以支持 Tailwind 实用过渡。这旨在嵌套在 TransitionGroup 组件中,以支持多个项目(例如列表)的动画。
我能够顺利地执行退出动画,但进入动画无法正常工作。你能帮我找出这段代码中的错误吗?
react 16.13.1 react-transition-group 4.4.1
沙盒:https://codesandbox.io/s/delicate-feather-ymozq
(登录那里查看 div 引用,以防类没有被应用,但它们似乎工作正常)
import React, { ReactNode } from "react";
import { Transition as ReactTransition } from "react-transition-group";
interface TransitionProps {
in?: boolean;
timeout: number;
enter?: string;
enterFrom?: string;
enterTo?: string;
leave?: string;
leaveFrom?: string;
leaveTo?: string;
children: ReactNode;
}
export function CSSTransition(props: TransitionProps) {
const { enter, enterFrom, enterTo, leave, leaveFrom, leaveTo } = props;
const nodeRef = React.useRef<HTMLDivElement>(null);
const enterClasses = splitClasses(enter);
const enterFromClasses = splitClasses(enterFrom);
const enterToClasses = splitClasses(enterTo);
const leaveClasses = splitClasses(leave);
const leaveFromClasses = splitClasses(leaveFrom);
const leaveToClasses = splitClasses(leaveTo);
function splitClasses(string: string | undefined): string[] {
if (string) return string.split(" ").filter((s) => s.length);
return [];
}
function addClasses(classes: string[]) {
nodeRef.current?.classList.add(...classes);
}
function removeClasses(classes: string[]) {
nodeRef.current?.classList.remove(...classes);
}
return (
<ReactTransition
in={props.in}
nodeRef={nodeRef}
timeout={props.timeout}
unmountOnExit
onEnter={() => {
console.log("onEnter", nodeRef);
addClasses([...enterClasses, ...enterFromClasses]);
}}
onEntering={() => {
console.log("onEntering", nodeRef);
removeClasses(enterFromClasses);
addClasses(enterToClasses);
}}
onEntered={() => {
console.log("onEntered", nodeRef);
removeClasses([...enterToClasses, ...enterClasses]);
}}
onExit={() => {
console.log("onExit", nodeRef);
addClasses([...leaveClasses, ...leaveFromClasses]);
}}
onExiting={() => {
console.log("onExiting", nodeRef);
removeClasses(leaveFromClasses);
addClasses(leaveToClasses);
}}
onExited={() => {
console.log("onExited", nodeRef);
removeClasses([...leaveToClasses, ...leaveClasses]);
}}
>
<div ref={nodeRef}>{props.children}</div>
</ReactTransition>
);
}
答案#1
解决方案:
在 CSSTransition.tsx 中,更改
import { Transition as ReactTransition } from "react-transition-group";
到
import { CSSTransition as ReactTransition } from "react-transition-group";
解释:
Tailwind 类名依赖于 CSS 动画。
Transition 并不是为 CSS 动画设计的,因为 onEnter 和 onEntering 方法被调用得非常快,以至于它们之间不会发生 DOM 重绘(动画的一帧)。因此,你为 enterTo 设置的所有类会立即被应用,而没有任何过渡到它们的机会。
另一方面,CSS Transition 在创建元素时会添加一个 -enter 类,然后在 下一个时钟/帧 添加一个 -enter-active。最后,在超时之后,它会移除所有类,只保留添加一个 -done 类。
-enter 和 -enter-active 类之间的过渡是允许 CSS 过渡发生的关键。这些类之间会增加一个计时/帧,这使库能够强制重新绘制。这个重新绘制会强制 onEntering 类如预期地过渡到 onEntered 类。
换句话说,Transition 会立即切换到 enterTo 状态,而 CSSTransition 在类切换之间会给出一帧时间,这是动画得以发生所需的。
DOM 通常以每秒最多 60 帧的速度进行动画/变化(取决于实现方式/最终用户的屏幕刷新率),每帧留出 16 毫秒;它不关心这 16 毫秒之间发生的事情。如果类更改后的最终状态是你的 enterTo 状态,而不是你的 enterFrom 状态,它将忽略 enterFrom 状态,从而永远不会显示 Tailwind 动画。
来源:
- React 过渡组文档
- React 过渡组重绘代码
- Tailwind 类添加的示例
