首先搭建項目需要先通過步驟搭建一個vue的項目,然后創建一個component文件,里面新建一個index.vue頁面來。
這是引入的element-ui組件庫里的組件,來實現我的路由,渲染的是我存儲的動態路由,所以需要先安裝并且引用。
npm install element-plus @element-plus/icons-vue
這是菜單管理的
<template><div class="sidebar-container"><!-- 折疊控制 --><div class="collapse-control" style="background-color:#293246" @click="toggleCollapse"><el-icon :size="20" :color="isCollapse ? '#fff' : '#ffd04b'"><component :is="isCollapse ? Expand : Fold" /></el-icon></div><!-- 導航菜單 --><div><el-menu router :default-active="$route.path" background-color="#293246" text-color="#fff" style="height: 100vh"active-text-color="#ffd04b" :collapse="isCollapse"><template v-for="menu in menuArray" :key="menu.path"><!-- 有子級的多層菜單項 --><el-sub-menu v-if="menu.children?.length" index="/layout"><template #title><span>{{ menu.meta.title }}</span></template><el-menu-item v-for="sub in menu.children" :key="'/layout' + sub.path" :index="'/layout' + sub.path"><span>{{ sub.title }}</span></el-menu-item></el-sub-menu><!-- 沒子級的單層菜單項 --><el-menu-item v-else :index="menu.path == '/home' ? menu.path : menu.path"><span>{{ menu.meta.title }}</span></el-menu-item></template></el-menu></div></div>
</template>
<script setup>
import { ref } from 'vue'
import { Expand, Fold } from '@element-plus/icons-vue'
const isCollapse = ref(false)
const toggleCollapse = () => {isCollapse.value = !isCollapse.value
}
const menuArray = ref([]);
render();//初始化渲染
function render() {try {const menuList = JSON.parse(sessionStorage.getItem('menuPath') || '[]');const menuName = JSON.parse(sessionStorage.getItem('menuName') || '[]');console.log(menuList, menuName);if (!Array.isArray(menuList) || !Array.isArray(menuName)) {throw new Error('存儲數據格式不正確');}const nameMap = new Map(menuName.map(item => [item.name, item]));menuArray.value = menuList.filter(item => item?.name && nameMap.has(item.name)).map(item => ({...item,...nameMap.get(item.name)}));console.log('安全篩選結果:', menuArray.value);} catch (error) {console.error('數據處理失敗:', error);// 可以在這里設置默認值或進行錯誤上報return [];}
}
</script>
<style scoped>
.sidebar-container {transition: width 0.3s;
}.collapse-control {padding: 15px;cursor: pointer;border-bottom: 1px solid #1f2d3d;
}.el-menu--collapse {width: 64px;
}.el-menu-vertical-demo:not(.el-menu--collapse) {width: 200px;
}
</style>
組件面包屑
<template><!-- <div style="margin-bottom: 20px;width: 100%;"><el-button size="small" @click="addTab(editableTabsValue)">添加標簽頁</el-button></div> --><el-tabs v-model="editableTabsValue" @tab-click="tabBread" type="card" @tab-remove="removeTab"><el-tab-pane v-for="item in editableTabs" :key="item.name" :label="item.title":name="item.name" :closable="item.name !== '/home'"><!-- 主頁面 --><el-main><router-view /></el-main></el-tab-pane></el-tabs>
</template><script setup>
import { ref, reactive, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';const route = useRoute();
const router = useRouter();const editableTabsValue = ref(route.path);
const editableTabs = reactive([{ title: '首頁', name: '/home' }
]);// 監聽路由變化,同步標簽頁
watch(() => route.path,(newPath) => {editableTabsValue.value = newPath;if (!editableTabs.some(tab => tab.name === newPath)) {const title = getTitleFromPath(newPath);editableTabs.push({ title, name: newPath });}},{ immediate: true }
);function getTitleFromPath(path) {const titleMap = {'/home': '首頁','/layout/user/list': '用戶列表','/layout/user/role': '角色列表',// 擴展其他路由...};return titleMap[path] || '新標簽';
}
// 點擊面包屑標簽跳轉路由
const tabBread = () => {console.log(editableTabsValue.value);router.push(editableTabsValue.value);
}
const removeTab = (targetName) => {const tabs = editableTabs;let activeName = editableTabsValue.value;if (activeName === targetName) {const currentIndex = tabs.findIndex(tab => tab.name === targetName);const nextTab = tabs[currentIndex + 1] || tabs[currentIndex - 1];activeName = nextTab?.name || '/home';router.push(activeName);}editableTabsValue.value = activeName;editableTabs.splice(0, editableTabs.length, ...tabs.filter(tab => tab.name !== targetName));
};
</script><style scoped>
/* 可以添加自定義樣式 */
.el-tabs {margin: 20px;
}
</style>
這部分代碼是用來布局菜單框架結構的,然后我們在路由部分引入這個文件的路由即可。
<!-- src/layouts/MainLayout.vue -->
<template><div class="app"><el-container style="height: 100vh;"><!-- 左側導航欄 --><el-aside width="200px"><aside-nav /></el-aside><div class="menu"><!-- 頂部菜單 --><MyHeader /></div></el-container></div>
</template><script>
import MyHeader from '@/Layout/topHeader.vue'
import AsideNav from '@/components/MenuItem.vue'export default {components: {MyHeader,AsideNav}
}
</script><style>
html,
body {padding: 0;margin: 0;
}.menu {width: 100%;
}
</style>