实现侧边栏分组展开折叠状态持久化记忆

This commit is contained in:
yml2213
2026-08-04 11:27:40 +08:00
parent aa2eac8d51
commit 54f05c15a4
+40 -8
View File
@@ -170,8 +170,29 @@ function getInitialOpenKeys(sections: SidebarSection[], selectedKey: string) {
.map((section) => section.key)
}
const SIDEBAR_OPEN_KEYS_KEY = 'sidebar_open_keys'
const SIDEBAR_COLLAPSED_KEY = 'sidebar_collapsed'
function loadStoredOpenKeys(sections: SidebarSection[], selectedKey: string): string[] {
const initial = getInitialOpenKeys(sections, selectedKey)
try {
const raw = localStorage.getItem(SIDEBAR_OPEN_KEYS_KEY)
if (raw) {
const parsed = JSON.parse(raw)
if (Array.isArray(parsed)) {
return Array.from(new Set([...parsed, ...initial]))
}
}
} catch (e) {
// ignore
}
return initial
}
export default function MainLayout() {
const [collapsed, setCollapsed] = useState(false)
const [collapsed, setCollapsed] = useState<boolean>(() => {
return localStorage.getItem(SIDEBAR_COLLAPSED_KEY) === 'true'
})
const { user, logout, isAdmin } = useAuth()
const navigate = useNavigate()
const location = useLocation()
@@ -179,11 +200,15 @@ export default function MainLayout() {
const sections = useMemo(() => (isAdmin ? adminSections : merchantSections), [isAdmin])
const selectedKey = getSelectedKey(location.pathname, location.search)
const [openKeys, setOpenKeys] = useState<string[]>(() => getInitialOpenKeys(sections, selectedKey))
const [openKeys, setOpenKeys] = useState<string[]>(() => loadStoredOpenKeys(sections, selectedKey))
useEffect(() => {
const nextOpenKeys = getInitialOpenKeys(sections, selectedKey)
setOpenKeys((current) => Array.from(new Set([...current, ...nextOpenKeys])))
setOpenKeys((current) => {
const merged = Array.from(new Set([...current, ...nextOpenKeys]))
localStorage.setItem(SIDEBAR_OPEN_KEYS_KEY, JSON.stringify(merged))
return merged
})
}, [sections, selectedKey])
const toggleSection = (section: SidebarSection) => {
@@ -197,11 +222,18 @@ export default function MainLayout() {
if (firstEnabledChild?.path) navigate(firstEnabledChild.path)
return
}
setOpenKeys((current) =>
current.includes(section.key)
setOpenKeys((current) => {
const next = current.includes(section.key)
? current.filter((key) => key !== section.key)
: [...current, section.key],
)
: [...current, section.key]
localStorage.setItem(SIDEBAR_OPEN_KEYS_KEY, JSON.stringify(next))
return next
})
}
const handleToggleCollapse = (next: boolean) => {
setCollapsed(next)
localStorage.setItem(SIDEBAR_COLLAPSED_KEY, String(next))
}
const handleChildClick = (child: SidebarChild) => {
@@ -300,7 +332,7 @@ export default function MainLayout() {
<button
className="app-header__collapse"
type="button"
onClick={() => setCollapsed(!collapsed)}
onClick={() => handleToggleCollapse(!collapsed)}
aria-label={collapsed ? '展开侧边栏' : '收起侧边栏'}
title={collapsed ? '展开侧边栏' : '收起侧边栏'}
>