AppSidebar.vue 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. <template>
  2. <aside class="app-sidebar">
  3. <div
  4. v-for="group in menuGroups"
  5. :key="group.key"
  6. class="app-sidebar-group"
  7. >
  8. <div class="app-sidebar-group-title">{{ group.label }}</div>
  9. <button
  10. v-for="item in group.children"
  11. :key="item.key"
  12. type="button"
  13. class="app-sidebar-item"
  14. :class="{ 'is-active': item.key === activeKey }"
  15. @click="handleClick(item)"
  16. >
  17. {{ item.label }}
  18. </button>
  19. </div>
  20. </aside>
  21. </template>
  22. <script setup>
  23. import { computed } from "vue";
  24. import { useRoute, useRouter } from "vue-router";
  25. defineOptions({
  26. name: "AppSidebar",
  27. });
  28. const route = useRoute();
  29. const router = useRouter();
  30. const menuGroups = [
  31. {
  32. key: "project",
  33. label: "项目管理",
  34. children: [
  35. { key: "overview", label: "项目概览", routeName: "overview" },
  36. { key: "detail", label: "项目明细", routeName: "projectDetail" },
  37. { key: "map", label: "一张图", routeName: "oneMap" },
  38. { key: "plan", label: "总体计划", routeName: "overallPlan" },
  39. ],
  40. },
  41. {
  42. key: "settings",
  43. label: "设置",
  44. children: [
  45. { key: "permission", label: "权限管理", routeName: "permission" },
  46. ],
  47. },
  48. ];
  49. const activeKey = computed(() => {
  50. const name = route.name;
  51. for (const group of menuGroups) {
  52. const matched = group.children.find((item) => item.routeName === name);
  53. if (matched) return matched.key;
  54. }
  55. return "overview";
  56. });
  57. const handleClick = (item) => {
  58. if (!item.routeName || item.routeName === route.name) return;
  59. router.push({ name: item.routeName });
  60. };
  61. </script>
  62. <style scoped lang="scss">
  63. .app-sidebar {
  64. box-sizing: border-box;
  65. flex-shrink: 0;
  66. width: 220px;
  67. background: #e8edf3;
  68. color: #16213a;
  69. }
  70. .app-sidebar-group {
  71. display: flex;
  72. flex-direction: column;
  73. }
  74. .app-sidebar-group-title {
  75. padding: 16px 16px 8px;
  76. font-size: 12px;
  77. color: #808695;
  78. }
  79. .app-sidebar-item {
  80. margin: 0;
  81. padding: 12px 16px;
  82. border: none;
  83. background: transparent;
  84. text-align: left;
  85. cursor: pointer;
  86. color: inherit;
  87. &.is-active {
  88. background: #d6e6f8;
  89. color: #2382e7;
  90. }
  91. }
  92. </style>