import{_ as i,o as a,c as n,a2 as l}from"./chunks/framework.B-QBKwc1.js";const c=JSON.parse('{"title":"布局系统","description":"前端布局采用经典的企业后台布局:左侧菜单 + 顶部导航 + 内容区域,支持多标签页导航。","frontmatter":{},"headers":[],"relativePath":"zh/frontend/layout.md","filePath":"zh/frontend/layout.md"}'),t={name:"zh/frontend/layout.md"};function p(e,s,h,k,r,d){return a(),n("div",null,[...s[0]||(s[0]=[l(`
概述
前端布局采用经典的企业后台布局:左侧菜单 + 顶部导航 + 内容区域,支持多标签页导航。
┌─────────────────────────────────────────────────────────────┐
│ 顶部导航栏 │
│ [Logo] [面包屑] [搜索] [通知] [头像] │
├──────────┬──────────────────────────────────────────────────┤
│ │ │
│ 侧边栏 │ 内容区域 │
│ 菜单 │ │
│ │ ┌──────────────────────────────────────────┐ │
│ ──────── │ │ 标签页导航 │ │
│ 系统管理 │ ├──────────────────────────────────────────┤ │
│ ├ 用户 │ │ │ │
│ ├ 角色 │ │ 页面内容 │ │
│ └ 菜单 │ │ │ │
│ │ │ │ │
│ 内容管理 │ │ │ │
│ ├ 文章 │ │ │ │
│ └ 分类 │ │ │ │
│ │ └──────────────────────────────────────────┘ │
└──────────┴──────────────────────────────────────────────────┘ui/src/layout/
├── index.vue # 布局入口
├── parentLayout.vue # 父级布局(路由嵌套用)
└── components/
├── Header/ # 顶部导航(AmendPwd 修改密码、Notifier 通知、ProjectSetting 项目设置)
├── Sider/ # 侧边栏菜单(动态菜单、折叠、主题)
├── Main/ # 内容区域(keep-alive 缓存)
├── TagsView/ # 标签页导航(多标签切换、关闭)
├── Logo/ # 品牌标识
└── Footer/ # 页脚菜单数据从后端 GET /api/index/getMenus 接口获取,由 asyncRouteStore 管理:
// 菜单渲染逻辑
const menuList = asyncRouteStore.getMenus;
// 菜单数据结构
interface MenuItem {
id: number;
parentId: number;
name: string;
path: string;
component: string;
icon: string;
sort: number;
hide: boolean;
children?: MenuItem[];
}菜单数据即路由
侧边栏与动态路由消费同一份 getMenus 数据(仅 type=0 可导航节点、status=0、hide=0、is_delete=0)——菜单管理里改 hide 即可隐藏入口而不删除路由。见 9.5 路由与动态菜单。
标签页自动记录访问过的页面,支持:
// 标签页 Store
const tabsViewStore = useTabsViewStore();
// 添加标签
tabsViewStore.addTab(route);
// 关闭标签
tabsViewStore.removeTab(route);(keep-alive 组件列表由路由守卫 afterEach 统一维护,见 9.5 路由与动态菜单。)
布局支持桌面端和平板端:
// 侧边栏折叠状态
const collapsed = ref(false);
// 响应式检测
const { width } = useWindowSize();
watchEffect(() => {
collapsed.value = width.value < 1024;
});