效果图

image.png
上下滚动
image.png

5-1 修改sidebar

sidebar组件中添加scrollPanel组件

src/layout/components/Sidebar/index.vue
image.png

  1. <template>
  2. <div class="sidebar-wrapper">
  3. <logo v-if="showLogo" :collapse="isCollapse" />
  4. <scroll-panel>
  5. <el-menu
  6. class="sidebar-container-menu"
  7. :class="{
  8. 'sidebar-show-logo': showLogo
  9. }"
  10. mode="vertical"
  11. :default-active="activeMenu"
  12. :background-color="scssVariables.menuBg"
  13. :text-color="scssVariables.menuText"
  14. :active-text-color="themeColor"
  15. :collapse="isCollapse"
  16. :collapse-transition="true"
  17. >
  18. <sidebar-item
  19. v-for="route in menuRoutes"
  20. :key="route.path"
  21. :item="route"
  22. :base-path="route.path"
  23. />
  24. </el-menu>
  25. </scroll-panel>
  26. </div>
  27. </template>
  28. <script lang="ts">
  29. import { defineComponent, computed } from 'vue'
  30. import { useRoute } from 'vue-router'
  31. import variables from '@/styles/variables.scss'
  32. import { routes } from '@/router'
  33. import SidebarItem from './SidebarItem.vue'
  34. import { useStore } from '@/store'
  35. import Logo from './Logo.vue'
  36. import ScrollPanel from '@/components/ScrollPanel.vue'
  37. export default defineComponent({
  38. name: 'Sidebar',
  39. components: {
  40. Logo,
  41. SidebarItem,
  42. ScrollPanel
  43. },
  44. setup() {
  45. const route = useRoute()
  46. const store = useStore()
  47. // 根据路由路径 对应 当前激活的菜单
  48. const activeMenu = computed(() => {
  49. const { path, meta } = route
  50. // 可根据meta.activeMenu指定 当前路由激活时 让哪个菜单高亮选中
  51. if (meta.activeMenu) {
  52. return meta.activeMenu
  53. }
  54. return path
  55. })
  56. // scss变量
  57. const scssVariables = computed(() => variables)
  58. // 展开收起状态 稍后放store 当前是展开就让它收起
  59. const isCollapse = computed(() => !store.getters.sidebar.opened)
  60. // 渲染路由
  61. const menuRoutes = computed(() => routes)
  62. // 获取主题色
  63. const themeColor = computed(() => store.getters.themeColor)
  64. // 是否显示logo
  65. const showLogo = computed(() => store.state.settings.sidebarLogo)
  66. return {
  67. // ...toRefs(variables), // 不有toRefs原因 缺点variables里面变量属性来源不明确
  68. scssVariables,
  69. isCollapse,
  70. activeMenu,
  71. menuRoutes,
  72. themeColor,
  73. showLogo
  74. }
  75. }
  76. })
  77. </script>
  78. <style lang="scss" scoped>
  79. .sidebar-wrapper {
  80. .sidebar-container-menu {
  81. height: 100vh;
  82. &.sidebar-show-logo {
  83. height: calc(100vh - 50px);
  84. }
  85. }
  86. }
  87. </style>

5-2 scrollPanel组件

之前在tagsview文件夹里就有scrollPanel组件, 可以共用一个, 从layout/compoents/TagsView里 把ScrollPanel.vue移动到src/compoents里

image.png
src/layout/components/TagsView/index.vue 修改导入路径
image.png

5-3 随便添加点测试路由

src/router/index.ts
image.png

  1. import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'
  2. import Layout from '@/layout/index.vue'
  3. // 看作是异步获取路由
  4. export const asyncRoutes: Array<RouteRecordRaw> = [
  5. {
  6. path: '/documentation',
  7. component: Layout, // 布局组件作为一级路由
  8. redirect: '/documentation/index',
  9. children: [
  10. {
  11. path: 'index',
  12. name: 'Documentation',
  13. component: () => import(/* webpackChunkName: "documentation" */ '@/views/documentation/index.vue'),
  14. meta: {
  15. title: 'Documentation',
  16. icon: 'documentation',
  17. hidden: false, // 菜单栏不显示
  18. // 路由是否缓存 没有这个属性或false都会缓存 true不缓存
  19. noCache: false
  20. }
  21. }
  22. ]
  23. },
  24. {
  25. path: '/guide',
  26. component: Layout,
  27. redirect: '/guide/index',
  28. children: [
  29. {
  30. path: 'index',
  31. name: 'Guide',
  32. component: () => import(/* webpackChunkName: "guide" */ '@/views/guide/index.vue'),
  33. meta: {
  34. title: 'Guide',
  35. icon: 'guide'
  36. // 当guide路由激活时高亮选中的是 documentation/index菜单
  37. // activeMenu: '/documentation/index'
  38. }
  39. }
  40. ]
  41. },
  42. {
  43. path: '/system',
  44. component: Layout,
  45. redirect: '/system/user',
  46. meta: {
  47. title: 'System',
  48. icon: 'lock',
  49. alwaysShow: true // 根路由始终显示 哪怕只有一个子路由
  50. },
  51. children: [
  52. {
  53. path: 'menu',
  54. name: 'Menu Management',
  55. component: () => import(/* webpackChunkName: "menu" */ '@/views/system/menu.vue'),
  56. meta: {
  57. title: 'Menu Management',
  58. hidden: false,
  59. breadcrumb: false
  60. }
  61. },
  62. {
  63. path: 'role',
  64. name: 'Role Management',
  65. component: () => import(/* webpackChunkName: "role" */ '@/views/system/role.vue'),
  66. meta: {
  67. title: 'Role Management',
  68. hidden: false
  69. }
  70. },
  71. {
  72. path: 'user',
  73. name: 'User Management',
  74. component: () => import(/* webpackChunkName: "user" */ '@/views/system/user.vue'),
  75. meta: {
  76. title: 'User Management'
  77. }
  78. }
  79. ]
  80. },
  81. { // 外链路由
  82. path: '/external-link',
  83. component: Layout,
  84. children: [
  85. {
  86. path: 'https://www.baidu.com/',
  87. redirect: '/',
  88. meta: {
  89. title: 'External Link',
  90. icon: 'link'
  91. }
  92. }
  93. ]
  94. },
  95. { // 404一定放在要在最后面
  96. path: '/:pathMatch(.*)*',
  97. redirect: '/404',
  98. meta: {
  99. hidden: true
  100. }
  101. }
  102. ]
  103. export const constantRoutes: Array<RouteRecordRaw> = [
  104. {
  105. path: '/',
  106. component: Layout,
  107. redirect: '/dashboard',
  108. children: [
  109. {
  110. path: 'dashboard',
  111. name: 'Dashboard',
  112. component: () => import(/* webpackChunkName: "dashboard" */ '@/views/dashboard/index.vue'),
  113. meta: {
  114. title: 'Dashboard',
  115. // icon: 'dashboard'
  116. icon: 'el-icon-platform-eleme',
  117. affix: true // 固定显示在tagsView中
  118. }
  119. }
  120. ]
  121. },
  122. {
  123. path: '/redirect',
  124. component: Layout,
  125. meta: {
  126. hidden: true
  127. },
  128. children: [
  129. { // 带参数的动态路由正则匹配
  130. // https://next.router.vuejs.org/zh/guide/essentials/route-matching-syntax.html#%E5%8F%AF%E9%87%8D%E5%A4%8D%E7%9A%84%E5%8F%82%E6%95%B0
  131. path: '/redirect/:path(.*)', // 要匹配多级路由 应该加*号
  132. component: () => import('@/views/redirect/index.vue')
  133. }
  134. ]
  135. },
  136. {
  137. path: '/401',
  138. component: Layout,
  139. children: [
  140. {
  141. path: '',
  142. component: () => import('@/views/error-page/401.vue'),
  143. meta: {
  144. title: '401',
  145. icon: '404',
  146. hidden: true
  147. }
  148. }
  149. ]
  150. },
  151. {
  152. path: '/404',
  153. component: () => import('@/views/error-page/404.vue'),
  154. meta: {
  155. hidden: true // 404 hidden掉
  156. }
  157. },
  158. // 以下都是测试路由 测完可以删了
  159. {
  160. path: '/menu',
  161. name: 'Menu Management1',
  162. component: () => import(/* webpackChunkName: "menu" */ '@/views/system/menu.vue'),
  163. meta: {
  164. title: 'Menu Management1',
  165. hidden: false,
  166. breadcrumb: false
  167. }
  168. },
  169. {
  170. path: '/role',
  171. name: 'Role Management1',
  172. component: () => import(/* webpackChunkName: "role" */ '@/views/system/role.vue'),
  173. meta: {
  174. title: 'Role Management1',
  175. hidden: false
  176. }
  177. },
  178. {
  179. path: '/user',
  180. name: 'User Management1',
  181. component: () => import(/* webpackChunkName: "user" */ '@/views/system/user.vue'),
  182. meta: {
  183. title: 'User Management1'
  184. }
  185. },
  186. {
  187. path: '/menu',
  188. name: 'Menu Management2',
  189. component: () => import(/* webpackChunkName: "menu" */ '@/views/system/menu.vue'),
  190. meta: {
  191. title: 'Menu Management2',
  192. hidden: false,
  193. breadcrumb: false
  194. }
  195. },
  196. {
  197. path: '/role',
  198. name: 'Role Management2',
  199. component: () => import(/* webpackChunkName: "role" */ '@/views/system/role.vue'),
  200. meta: {
  201. title: 'Role Management2',
  202. hidden: false
  203. }
  204. },
  205. {
  206. path: '/user',
  207. name: 'User Management2',
  208. component: () => import(/* webpackChunkName: "user" */ '@/views/system/user.vue'),
  209. meta: {
  210. title: 'User Management2'
  211. }
  212. },
  213. {
  214. path: '/menu',
  215. name: 'Menu Management3',
  216. component: () => import(/* webpackChunkName: "menu" */ '@/views/system/menu.vue'),
  217. meta: {
  218. title: 'Menu Management3',
  219. hidden: false,
  220. breadcrumb: false
  221. }
  222. },
  223. {
  224. path: '/role',
  225. name: 'Role Management3',
  226. component: () => import(/* webpackChunkName: "role" */ '@/views/system/role.vue'),
  227. meta: {
  228. title: 'Role Management4',
  229. hidden: false
  230. }
  231. },
  232. {
  233. path: '/user',
  234. name: 'User Management3',
  235. component: () => import(/* webpackChunkName: "user" */ '@/views/system/user.vue'),
  236. meta: {
  237. title: 'User Management3'
  238. }
  239. },
  240. {
  241. path: '/menu',
  242. name: 'Menu Management4',
  243. component: () => import(/* webpackChunkName: "menu" */ '@/views/system/menu.vue'),
  244. meta: {
  245. title: 'Menu Management4',
  246. hidden: false,
  247. breadcrumb: false
  248. }
  249. },
  250. {
  251. path: '/role',
  252. name: 'Role Management4',
  253. component: () => import(/* webpackChunkName: "role" */ '@/views/system/role.vue'),
  254. meta: {
  255. title: 'Role Management4',
  256. hidden: false
  257. }
  258. },
  259. {
  260. path: '/user',
  261. name: 'User Management4',
  262. component: () => import(/* webpackChunkName: "user" */ '@/views/system/user.vue'),
  263. meta: {
  264. title: 'User Management4'
  265. }
  266. },
  267. {
  268. path: '/role',
  269. name: 'Role Management5',
  270. component: () => import(/* webpackChunkName: "role" */ '@/views/system/role.vue'),
  271. meta: {
  272. title: 'Role Management5',
  273. hidden: false
  274. }
  275. },
  276. {
  277. path: '/user',
  278. name: 'User Management5',
  279. component: () => import(/* webpackChunkName: "user" */ '@/views/system/user.vue'),
  280. meta: {
  281. title: 'User Management5'
  282. }
  283. }
  284. ]
  285. export const routes = [
  286. ...constantRoutes,
  287. ...asyncRoutes
  288. ]
  289. const router = createRouter({
  290. history: createWebHashHistory(),
  291. routes
  292. })
  293. export default router

测试完滚动 测试的路由都可以删了