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

如何为React+TailwindCSS侧边栏添加关闭动画?

侧边栏关闭动画失效的解决方案

问题根源

当前实现中,侧边栏的渲染完全依赖sidebarOpen状态——当状态变为false时,组件直接从DOM中卸载,关闭动画根本没机会执行。另外,手动操作内联样式的方式也容易导致动画逻辑混乱。

优化方案

调整逻辑:先触发关闭动画,等动画执行完成后再移除侧边栏组件;同时用CSS类统一管理动画状态,替代繁琐的内联样式操作。

修改后的Menu组件代码

import React, { useRef, useState, useEffect } from 'react';
import Sidebar from "./Sidebar";

const Menu = ({ sidebarOpen, toggleSidebar }) => {
    const [showSidebar, setShowSidebar] = useState(sidebarOpen);
    const sidebarRef = useRef(null);

    // 同步外部传入的sidebarOpen状态
    useEffect(() => {
        if (sidebarOpen) {
            setShowSidebar(true);
            document.body.classList.add("sidebar-open");
            document.body.style.overflow = "hidden";
        } else {
            // 触发关闭动画
            if (sidebarRef.current) {
                sidebarRef.current.classList.add('sidebar-slide-out');
            }
            document.body.style.overflow = "auto";
        }
    }, [sidebarOpen]);

    // 监听关闭动画结束事件
    useEffect(() => {
        const handleAnimationEnd = (e) => {
            if (e.propertyName === 'transform' && !sidebarOpen) {
                setShowSidebar(false);
                document.body.classList.remove("sidebar-open");
                sidebarRef.current?.classList.remove('sidebar-slide-out');
            }
        };

        const sidebarEl = sidebarRef.current;
        if (sidebarEl) {
            sidebarEl.addEventListener('transitionend', handleAnimationEnd);
        }

        return () => {
            sidebarEl?.removeEventListener('transitionend', handleAnimationEnd);
        };
    }, [sidebarOpen]);

    const handleToggleSidebar = () => {
        toggleSidebar(!sidebarOpen);
    };

    return (
        <div className="fixed bottom-0 left-0 w-full bg-white z-50 border-t-1 border-green-900">
            <div className="h-[60px] flex items-center justify-between">
                <div className="flex items-center ml-4">
                    <div
                        className="cursor-pointer p-3"
                        onClick={handleToggleSidebar}
                    >
                        <div className={`h-1 w-6 bg-green-700 rounded mb-1 ${sidebarOpen ? 'opacity-0' : ''}`}></div>
                        <div className={`h-1 w-6 bg-green-700 rounded mb-1 ${sidebarOpen ? 'opacity-0' : ''}`}></div>
                        <div className={`h-1 w-6 bg-green-700 rounded ${sidebarOpen ? 'opacity-0' : ''}`}></div>
                    </div>
                </div>
            </div>

            {showSidebar && (
                <>
                    <div 
                        className="fixed top-0 left-0 right-0 bottom-0 z-0 bg-gray-700 opacity-50 transition-opacity duration-300" 
                        onClick={() => toggleSidebar(false)}
                    ></div>
                    <div 
                        ref={sidebarRef}
                        className="fixed top-0 left-0 bottom-0 z-10 w-full max-w-[20rem] p-4 bg-white shadow-xl shadow-blue-gray-900/5 transform transition-transform duration-500 ease-in-out"
                    >
                        <Sidebar />
                    </div>
                </>
            )}
        </div>
    );
}

export default Menu;

添加自定义CSS类

在全局CSS中添加以下样式定义关闭动画:

body.sidebar-open {
  overflow: hidden;
}

.sidebar-slide-out {
  transform: translateX(-100%);
}

关键改进点

  • 分离状态控制:用本地showSidebar状态控制组件渲染,外部sidebarOpen状态只负责触发动画逻辑,确保动画完成后再卸载组件。
  • CSS类管理动画:用Tailwind的transition-transform和自定义类sidebar-slide-out实现动画,替代内联样式,逻辑更清晰。
  • 监听动画结束事件:通过transitionend事件准确捕捉动画完成时机,再更新状态隐藏组件。
  • 优化遮罩层动画:给遮罩层添加opacity过渡,让整体交互更流畅。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 17:10:21