You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js切换页面时Tailwind动画播放两次如何解决

问题:react-hot-toast 结合 tailwindcss-animate 实现告警动画淡入效果重复播放两次

问题场景

在项目中使用 react-hot-toast 实现页面切换时的告警提示与对应动画效果,在 tailwind.config.js 中引入 tailwindcss-animate 插件添加动画类,仅使用 animate-in、animate-out、fade-in、fade-out 四个动画类为自定义Success告警框实现动画时,淡入动画会重复播放两次,原始自定义组件代码如下:

import toast, { ToastOptions } from 'react-hot-toast';
import { CheckCircleIcon } from '@heroicons/react/outline';
import clsx from 'clsx';

interface ISuccess {
  message: string;
  options?: ToastOptions;
}

export const Success = ({ message, options }: ISuccess) => {
  toast.custom(
    (t) => (
      <div
        className={clsx(
          'flex rounded-lg bg-gray-900 py-2.5 px-3 shadow-lg ring-1 ring-black ring-opacity-5',
          {
            'animate-in fade-in': t.visible,
            'fade-out animate-out': !t.visible,
          }
        )}
      >
        <CheckCircleIcon className="h-6 w-6 text-gray-700" />
        <div className="ml-2 text-gray-300">{message}</div>
      </div>
    ),
    {
      duration: 250,
      ...options,
    }
  );
};

问题根因

  • 配置参数错误:将react-hot-toast的duration参数(即toast正常停留展示的时长)错误设置为250ms,时长和淡入动画默认时长接近,toast刚完成进场渲染就立刻触发离场状态切换,状态快速抖动导致动画被重复触发。
  • 缺少动画播放次数限制:tailwindcss-animate默认动画类未限制播放次数,页面切换引发的组件重渲染、toast内部显隐状态更新带来的类名重计算,都会触发浏览器重新启动动画。
  • 未配置离场动画预留时长:没有设置exitDuration参数,toast触发离场时没有预留足够的动画执行时间,DOM卸载逻辑和CSS动画执行逻辑冲突,进一步导致动画重复播放。

修复方案

按照以下步骤调整即可让动画仅播放一次:

  1. 修正toast时长配置,区分toast停留展示时长和进出场动画时长,设置和CSS动画时长匹配的exitDuration参数,给离场动画预留执行时间。
  2. 给动画元素添加animate-once类,强制动画仅播放1次,从CSS层面阻断重渲染触发的重复动画。
  3. 显式指定动画时长为200ms,添加fill-mode-forwards类保证动画结束后元素保持动画结束帧状态,避免状态跳变。

修复后的完整组件代码如下:

import toast, { ToastOptions } from 'react-hot-toast';
import { CheckCircleIcon } from '@heroicons/react/outline';
import clsx from 'clsx';

interface ISuccess {
  message: string;
  options?: ToastOptions;
}

export const Success = ({ message, options }: ISuccess) => {
  toast.custom(
    (t) => (
      <div
        className={clsx(
          'flex rounded-lg bg-gray-900 py-2.5 px-3 shadow-lg ring-1 ring-black ring-opacity-5 animate-once fill-mode-forwards',
          {
            'animate-in fade-in duration-200': t.visible,
            'animate-out fade-out duration-200': !t.visible,
          }
        )}
      >
        <CheckCircleIcon className="h-6 w-6 text-green-500" />
        <div className="ml-2 text-gray-300">{message}</div>
      </div>
    ),
    {
      duration: 2000, // toast展示停留时长,可根据业务需求自行调整
      exitDuration: 200, // 离场动画执行时长,和CSS动画时长保持一致
      ...options,
    }
  );
};

注:如果业务场景需要更短的toast停留时长,只要保证duration参数值大于进场动画时长即可,避免进场动画未完成就触发离场逻辑。

内容的提问来源于stack exchange,提问作者deadcoder0904

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 04:42:27