vue3+vit+vue-router路由,侧边栏菜单,面包屑导航设置层级结构
文章目录
- 注意
- 效果图
- 目录结构
- 代码
- vite.config.ts需要配置路径别名@符号
- main.ts
- App.vue
- Breadcrumb.vue面包屑组件
- menus.ts
- // src/router/index.ts
- 其他文件
注意
- 目录结构仅供参考
- DefaultLayout.vue 没有用到,我直接写在APP文件中
- vux-store我也没有用到,单独写了一个配置文件存储菜单数据
- 详细代码需要参考后面贴出来的实际代码
效果图
目录结构
src/
├── views/
│ ├── user/ # 用户管理模块
│ │ ├── UserList.vue # 用户列表页面(主页面)
│ │ ├── UserDetails.vue # 用户详情页面(子页面)
│ │ ├── UserEdit.vue # 用户编辑页面(子页面)
│ │ └── UserSettings.vue # 用户设置页面(子页面)
│ │
│ ├── role/ # 用户角色管理模块
│ │ └── UserRole.vue # 用户角色管理页面
│ │
│ ├── permission/ # 权限管理模块
│ │ ├── PermissionList.vue # 权限列表页面(主页面)
│ │ ├── PermissionAdd.vue # 权限添加页面(子页面)
│ │ └── PermissionSetting.vue # 权限设置页面(子页面)
│ │
│ └── layout/ # 布局组件
│ └── DefaultLayout.vue (没有) # 主布局,包含菜单和面包屑导航
│
├── router/
│ └── index.js # 路由配置文件
│
├── store/
│ └── modules/
│ └── menu.js (没有) # 动态菜单状态管理
│
└── components/└── breadcrumb/ # 面包屑组件└── Breadcrumb.vue
用户管理└── 用户列表(含详情、编辑)└── 用户角色管理└── 用户设置└── 偏好设置(有编辑页)└── 安全设置(有修改页)
src/
├── pages/
│ ├── user/
│ │ ├── UserList.vue
│ │ ├── UserDetails.vue
│ │ ├── UserEdit.vue
│ │ ├── UserSettings.vue # 用户设置主页面
│ │ ├── preferences/
│ │ │ ├── PreferenceSettings.vue # 偏好设置页面
│ │ │ └── PreferenceEdit.vue # 偏好编辑页面
│ │ └── security/
│ │ ├── SecuritySettings.vue # 安全设置页面
│ │ └── SecurityModify.vue # 安全修改页面
│ ├── role/
│ │ └── UserRole.vue
│ └── permission/
│ └── ...
代码
vite.config.ts需要配置路径别名@符号
import path from 'node:path'
import Vue from '@vitejs/plugin-vue'import Unocss from 'unocss/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import Components from 'unplugin-vue-components/vite'
import VueRouter from 'unplugin-vue-router/vite'import { defineConfig } from 'vite'// https://vitejs.dev/config/
export default defineConfig({resolve: {alias: {'@/': `${path.resolve(__dirname, 'src')}/`,},},css: {preprocessorOptions: {scss: {additionalData: `@use "@/styles/element/index.scss" as *;`,api: 'modern-compiler',},},},plugins: [Vue(),// https://github.com/posva/unplugin-vue-routerVueRouter({extensions: ['.vue', '.md'],dts: 'src/typed-router.d.ts',}),Components({// allow auto load markdown components under `./src/components/`extensions: ['vue', 'md'],// allow auto import and register components used in markdowninclude: [/\.vue$/, /\.vue\?vue/, /\.md$/],resolvers: [ElementPlusResolver({importStyle: 'sass',}),],dts: 'src/components.d.ts',}),// https://github.com/antfu/unocss// see uno.config.ts for configUnocss(),],ssr: {// TODO: workaround until they support native ESMnoExternal: ['element-plus'],},
})
main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import '@/styles/index.scss'
import 'uno.css'// If you want to use ElMessage, import it.
import 'element-plus/theme-chalk/src/message.scss'
import 'element-plus/theme-chalk/src/message-box.scss'const app = createApp(App)app.use(router)
app.use(ElementPlus)app.mount('#app')
App.vue
<!-- src/App.vue -->
<template><el-container class="layout-container"><!-- 左侧侧边栏 --><el-aside width="200px" class="layout-aside"><el-menudefault-active="$route.path"routerclass="side-menu"background-color="#ffffff"text-color="#333"active-text-color="#409EFF"><!-- 动态生成菜单 --><div v-for="menu in menus" :key="menu.title"><el-sub-menu :index="menu.title" v-if="menu.children && menu.children.length"><template #title>{{ menu.title }}</template><el-menu-itemv-for="child in menu.children":key="child.path":index="child.path">{{ child.title || child.path }}</el-menu-item></el-sub-menu></div></el-menu></el-aside><!-- 右侧主内容区域 --><el-container class="layout-main"><!-- 顶部栏 --><el-header class="layout-header"><div class="header-title">智能控制器后台系统</div><div class="header-right"><span>管理员</span><el-avatar icon="UserFilled" size="small" /></div></el-header><!-- 面包屑导航 --><el-header class="layout-breadcrumb"><Breadcrumb /></el-header><!-- 页面主体内容 --><el-main class="layout-content"><router-view /></el-main></el-container></el-container>
</template><script setup>import Breadcrumb from './components/breadcrumb/Breadcrumb.vue';
import { menus } from '@/config/menu';</script><style scoped>
.layout-container {height: 100vh;
}.layout-aside {background-color: #fff;border-right: 1px solid #e4e7ed;
}.layout-main {flex-direction: column;
}.layout-header {display: flex;justify-content: space-between;align-items: center;background-color: #ffffff;box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);padding: 0 20px;
}.header-title {font-size: 18px;font-weight: bold;
}.layout-breadcrumb {padding: 10px 20px;background-color: #f5f7fa;border-bottom: 1px solid #e4e7ed;
}.layout-content {padding: 20px;background-color: #f9fafb;
}
</style>
Breadcrumb.vue面包屑组件
<template><el-breadcrumb separator="/"><el-breadcrumb-item v-for="item in breadcrumbs" :to="item.path" :key="item.path">{{ item.meta?.title }}</el-breadcrumb-item></el-breadcrumb>
</template><script setup>
import { ref, onMounted, watch } from 'vue';
import { useRoute } from 'vue-router';const route = useRoute();
const breadcrumbs = ref([]);const getBreadcrumbs = () => {const matched = route.matched.filter(item => item.meta?.title);breadcrumbs.value = matched;console.log('breadcrumbs:', breadcrumbs.value);
};// 页面加载时获取一次
onMounted(() => {getBreadcrumbs();
});// 监听路由路径变化,动态更新面包屑
watch(() => route.path,() => {getBreadcrumbs();}
);
</script>
menus.ts
export const menus = [{title: '用户管理',children: [{ title: '用户列表', path: '/user/list' },{ title: '用户角色管理', path: '/user/role' }]},{title: '权限管理',children: [{ title: '权限列表', path: '/permission/list' }]}]
// src/router/index.ts
// src/router/index.ts
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
// import { CustomRoute } from '@/types/router';
export interface CustomRouteMeta {title: string;
}export type CustomRoute = Omit<RouteRecordRaw, 'meta' | 'children'> & {meta: CustomRouteMeta;children?: CustomRoute[];
};
const routes: CustomRoute[] = [{path: '/',redirect: '/user/list',meta: { title: '首页' },children: [// 用户管理 - 父级{path: '/user',redirect: '/user/list',meta: { title: '用户管理' },children: [{path: 'list',component: () => import('@/pages/user/UserList.vue'),meta: { title: '用户列表' }},{path: 'details/:id',component: () => import('@/pages/user/UserDetails.vue'),meta: { title: '用户详情' }},{path: 'edit/:id',component: () => import('@/pages/user/UserEdit.vue'),meta: { title: '用户编辑' }},{path: 'settings',component: () => import('@/pages/user/UserSettings.vue'),meta: { title: '用户设置' }},{path: 'role',component: () => import('@/pages/role/UserRole.vue'),meta: { title: '用户角色管理' }},{path: 'preferences',redirect: '/user/preferences/settings',meta: { title: '偏好设置' },children: [{path: 'settings',component: () => import('@/pages/user/preferences/PreferenceSettings.vue'),meta: { title: '偏好设置' }},{path: 'edit',component: () => import('@/pages/user/preferences/PreferenceEdit.vue'),meta: { title: '偏好编辑' }}]},{path: 'security',redirect: '/user/security/settings',meta: { title: '安全设置' },children: [{path: 'settings',component: () => import('@/pages/user/security/SecuritySettings.vue'),meta: { title: '安全设置' }},{path: 'modify',component: () => import('@/pages/user/security/SecurityModify.vue'),meta: { title: '安全修改' }}]}]},// 权限管理 - 父级{path: '/permission',redirect: '/permission/list',meta: { title: '权限管理' },children: [{path: 'list',component: () => import('@/pages/permission/PermissionList.vue'),meta: { title: '权限列表' }},{path: 'add',component: () => import('@/pages/permission/PermissionAdd.vue'),meta: { title: '权限添加' }},{path: 'setting',component: () => import('@/pages/permission/PermissionSetting.vue'),meta: { title: '权限设置' }}]}]},{path: '/:pathMatch(.*)*',name: 'NotFound',component: () => import('@/pages/error/404.vue'),meta: { title: '页面不存在' }}
];const router = createRouter({history: createWebHistory(),routes:routes as unknown as RouteRecordRaw[]
});export default router;
其他文件
│ │ ├── UserList.vue
│ │ ├── UserDetails.vue
│ │ ├── UserEdit.vue
│ │ ├── UserSettings.vue # 用户设置主页面
│ │ ├── preferences/
│ │ │ ├── PreferenceSettings.vue # 偏好设置页面
│ │ │ └── PreferenceEdit.vue # 偏好编辑页面
│ │ └── security/
│ │ ├── SecuritySettings.vue # 安全设置页面
│ │ └── SecurityModify.vue # 安全修改页面
│ │ ├── UserList.vue
<template><div><h2>用户列表</h2><button @click="goToDetail">查看用户详情</button><button @click="goToEdit">编辑用户信息</button><button @click="goToSettings">用户设置</button></div>
</template><script setup>
import { useRouter } from 'vue-router';const router = useRouter();
const goToDetail = () => router.push('/user/details/1');
const goToEdit = () => router.push('/user/edit/1');
const goToSettings = () => router.push('/user/settings');
</script>
│ │ ├── UserDetails.vue
<template><h1>用户详情</h1>
</template>
│ │ ├── UserEdit.vue
<template><h1>用户编辑</h1>
</template>
│ │ ├── UserSettings.vue # 用户设置主页面
<template><div><h2>用户设置</h2><router-link to="/user/preferences/settings"><el-button>进入偏好设置</el-button></router-link><router-link to="/user/security/settings"><el-button>进入安全设置</el-button></router-link><router-view /></div>
</template>
<script setup></script>
│ │ ├── preferences/
│ │ │ ├── PreferenceSettings.vue # 偏好设置页面
<template><div><h3>偏好设置</h3><router-link to="/user/preferences/edit"><el-button>编辑偏好设置</el-button></router-link></div>
</template>
│ │ │ └── PreferenceEdit.vue # 偏好编辑页面
<template><h1>偏好编辑页面</h1>
</template>
│ │ └── security/
│ │ ├── SecuritySettings.vue # 安全设置页面
<template><h1>安全设置页面</h1>
</template>
│ │ └── SecurityModify.vue # 安全修改页面
<template><h1>安全修改页面</h1>
</template>