- layoutConfig.js: 新增 LAYOUT_PADDING 常量 { base: 4, md: 6, lg: '80px' }
- MainLayout.js: 在 Outlet 容器上统一应用 px={LAYOUT_PADDING.x}
- HomeNavbar.js: 边距从 lg:8 改为 lg:'80px',与内容区对齐
- AppFooter.js: 移除 Container,边距改为 lg:'80px'
页面组件清理(移除冗余的 px/Container):
- Company, Community, Center, Profile, Settings
- ValueForum, DataBrowser, LimitAnalyse, StockOverview, Concept
特殊处理:
- CompanyHeader: 使用负边距实现全宽背景
- Concept Hero: 使用负边距实现全宽背景
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
69 lines
3.2 KiB
JavaScript
69 lines
3.2 KiB
JavaScript
// src/layouts/MainLayout.js
|
||
// 主布局组件 - 为所有带导航栏的页面提供统一布局
|
||
import React, { memo, Suspense } from "react";
|
||
import { Outlet } from "react-router-dom";
|
||
import { Box, Flex } from '@chakra-ui/react';
|
||
import HomeNavbar from "../components/Navbars/HomeNavbar";
|
||
import AppFooter from "./AppFooter";
|
||
import BackToTopButton from "./components/BackToTopButton";
|
||
import ErrorBoundary from "../components/ErrorBoundary";
|
||
import PageLoader from "../components/Loading/PageLoader";
|
||
import GlobalSidebar from "../components/GlobalSidebar";
|
||
import { BACK_TO_TOP_CONFIG, LAYOUT_SIZE, LAYOUT_PADDING } from "./config/layoutConfig";
|
||
|
||
// ✅ P0 性能优化:缓存静态组件,避免路由切换时不必要的重新渲染
|
||
// HomeNavbar (1623行) 和 AppFooter 不依赖路由参数,使用 memo 可大幅减少渲染次数
|
||
const MemoizedHomeNavbar = memo(HomeNavbar);
|
||
const MemoizedAppFooter = memo(AppFooter);
|
||
|
||
/**
|
||
* MainLayout - 带导航栏的主布局
|
||
*
|
||
* 使用 <Outlet /> 渲染子路由,确保导航栏只渲染一次
|
||
* 页面切换时只有 Outlet 内的内容会更新,导航栏保持不变
|
||
*
|
||
* 架构优化:
|
||
* - ✅ 组件拆分 - BackToTopButton 独立复用
|
||
* - ✅ 性能优化 - 使用 memo 避免导航栏和页脚重新渲染
|
||
* - ✅ 错误隔离 - ErrorBoundary 包裹页面内容,确保导航栏可用
|
||
* - ✅ 懒加载支持 - Suspense 统一处理懒加载
|
||
* - ✅ 布局简化 - 直接内联容器逻辑,减少嵌套层级
|
||
* - ✅ 全局侧边栏 - 右侧可收起的工具栏(关注股票、事件动态)
|
||
*/
|
||
export default function MainLayout() {
|
||
return (
|
||
<Box flex="1" h="100vh" w="100%" position="relative" display="flex" flexDirection="column" bg="#1A202C">
|
||
{/* 导航栏 - 在所有页面间共享,memo 后不会在路由切换时重新渲染 */}
|
||
<MemoizedHomeNavbar />
|
||
|
||
{/* 主体区域 - 页面内容 + 右侧全局侧边栏(绝对定位覆盖) */}
|
||
<Box flex="1" bg="#1A202C" position="relative" overflow="hidden">
|
||
{/* 页面内容区域 - 全宽度,与导航栏对齐 */}
|
||
<Box h="100%" overflowY="auto" display="flex" flexDirection="column">
|
||
<Box flex="1" pt={LAYOUT_SIZE.navbarHeight} px={LAYOUT_PADDING.x}>
|
||
<ErrorBoundary>
|
||
<Suspense fallback={<PageLoader message="页面加载中..." />}>
|
||
<Outlet />
|
||
</Suspense>
|
||
</ErrorBoundary>
|
||
</Box>
|
||
{/* 页脚 - 在滚动区域内,随内容滚动 */}
|
||
<MemoizedAppFooter />
|
||
</Box>
|
||
|
||
{/* 全局右侧工具栏 - 绝对定位覆盖在内容上方 */}
|
||
<Box position="absolute" top={0} right={0} bottom={0}>
|
||
<GlobalSidebar />
|
||
</Box>
|
||
</Box>
|
||
|
||
{/* 返回顶部按钮 - 滚动超过阈值时显示 */}
|
||
{/* <BackToTopButton
|
||
scrollThreshold={BACK_TO_TOP_CONFIG.scrollThreshold}
|
||
position={BACK_TO_TOP_CONFIG.position}
|
||
zIndex={BACK_TO_TOP_CONFIG.zIndex}
|
||
/> */}
|
||
</Box>
|
||
);
|
||
}
|