Procházet zdrojové kódy

refactor: 优化router

lvkun996 před 3 roky
rodič
revize
8962c4e7fe

+ 1 - 0
package.json

@@ -16,6 +16,7 @@
     "babel-plugin-import": "^1.13.6",
     "core-js": "^3.8.3",
     "mitt": "^3.0.0",
+    "path-browserify": "^1.0.1",
     "pinia": "^2.0.33",
     "vue": "^3.2.13",
     "vue-class-component": "^8.0.0-0",

+ 99 - 0
src/layout/components/Sidebar/SidebarItem.vue

@@ -0,0 +1,99 @@
+<template>
+  <template v-if="!item.hidden" >
+    <template
+      v-if="hasOneShowingChild(item.children, item)"
+    >
+      <a-menu-item :key="item.path" @click="changeRoute(item)" >
+        <user-outlined />
+        <span>{{item.name}}</span>
+      </a-menu-item>
+    </template>
+
+      <a-sub-menu v-else>
+        <template #title>
+          <user-outlined />
+          <span>
+            {{item.name}}
+          </span>
+        </template>
+        <sidebar-item
+          v-for="child in item.children"
+          :key="child.path"
+          :item="child"
+          :base-path="resolvePath(child.path)"
+        />
+      </a-sub-menu>
+  </template>
+</template>
+<!-- :base-path="resolvePath(child.path)" -->
+
+<script setup lang="ts" >
+import path from 'path-browserify'
+import { reactive, toRefs } from 'vue'
+import { useRouter } from 'vue-router'
+import { MenuFoldOutlined, MenuUnfoldOutlined, UserOutlined } from '@ant-design/icons-vue'
+
+const RootRouter = useRouter()
+const props = defineProps({
+  // 每一个router Item
+  item: {
+    type: Object,
+    required: true
+  },
+  // 基础路径,用于拼接
+  basePath: {
+    type: String,
+    default: ''
+  }
+})
+
+const changeRoute = (route: ROUTER.RoutesProps) => {
+  RootRouter.push(route.path)
+}
+
+const state = reactive({
+  onlyOneChild: null
+})
+
+const { onlyOneChild } = toRefs(state)
+
+const hasOneShowingChild = (children = [], parent: any) => {
+  const showingChildren = children.filter((item) => {
+    if (item.hidden) {
+      return false
+    } else {
+      state.onlyOneChild = item
+      return true
+    }
+  })
+
+  if (showingChildren.length === 1) {
+    return true
+  }
+
+  if (showingChildren.length === 0) {
+    state.onlyOneChild = { ...parent, path: '', noShowingChildren: true }
+    return true
+  }
+
+  return false
+}
+
+function isExternal (path: string) {
+  return /^(https?:|mailto:|tel:)/.test(path)
+}
+
+const resolvePath = (routePath: string) => {
+  if (isExternal(routePath)) {
+    return routePath
+  }
+  if (isExternal(props.basePath)) {
+    return props.basePath
+  }
+  return path.resolve(props.basePath, routePath)
+}
+</script>
+
+<style lang="less" >
+
+</style>

+ 55 - 0
src/layout/components/Sidebar/index.vue

@@ -0,0 +1,55 @@
+<template>
+  <a-row>
+    <a-col>
+      <a-layout-sider
+        :trigger="null"
+        v-model:collapsed="collapsed"
+        collapsible
+        style="background: #fff; height: 95%;"
+        breakpoint="lg"
+      >
+        <a-menu
+          :selectedKeys="selectedKeys2"
+          v-model:openKeys="openKeys"
+          mode="inline"
+          :style="{ height: '100%', borderRight: 0 }"
+        >
+          <sidebar-item
+            :item="route"
+            v-for="route in appRouter.router.sider.route"
+            :key="route.path"
+            :base-path="route.path"
+          />
+        </a-menu>
+      </a-layout-sider>
+    </a-col>
+  </a-row>
+</template>
+
+<script lang="ts" setup >
+
+import { ref } from 'vue'
+import { useAppRouter } from '@/store/router'
+import SidebarItem from './SidebarItem.vue'
+
+const appRouter = useAppRouter()
+
+console.log('appRouter.router.sider.route:', appRouter.router.sider.route)
+
+const collapsed = ref<boolean>(false)
+
+// const selectedKeys2 = ref<string[]>([appRouter.router.sider!.selectPath])
+// const openKeys = ref<string[]>(appRouter.router.sider!.openKeys)
+
+const selectedKeys2 = ref<string[]>([appRouter.router.sider!.selectPath])
+const openKeys = ref<string[]>(appRouter.router.sider!.openKeys)
+
+console.log(selectedKeys2, openKeys)
+
+</script>
+
+<style lang="less" scoped >
+/deep/ .ant-layout-sider-children {
+  margin-top: -4px;
+}
+</style>

+ 2 - 6
src/layout/layout.vue

@@ -2,7 +2,7 @@
     <a-layout class="a-layout" >
       <Navbar />
       <a-layout>
-      <Sider :router="silders" />
+      <SiderBar />
 
       <a-layout style="padding: 0 24px 24px; margin-top: 20px;overflow: hidden;overflow-y: scroll;padding-bottom: 40px;">
         <!-- <Breadcrumb /> -->
@@ -17,13 +17,9 @@
 </template>
 
 <script  lang="ts" setup >
-import router from '@/router/index'
 import Navbar from './navbar.vue'
-import Sider from './sider.vue'
+import SiderBar from './components/Sidebar/index.vue'
 import Breadcrumb from './breadcrumb.vue'
-
-const silders = router.options.routes.find(route => route.path === '/')?.children
-
 </script>
 
 <style>

+ 28 - 7
src/layout/sider.vue

@@ -18,7 +18,12 @@
             >
 
             <template v-for="item in appRouter.router.sider.route" :key="item.path">
-              <a-sub-menu  v-if="item.children && item.children.filter(_ => !_.hidden)" :key="item.path" >
+              <a-menu-item v-if="!item.children"  :key="item.path"  @click="changeRoute(item)" >
+                <user-outlined />
+                <span>{{item.name}}</span>
+              </a-menu-item>
+
+              <a-sub-menu  v-else >
                 <template #title>
                   <user-outlined />
                   <span>
@@ -29,10 +34,6 @@
                   <user-outlined />{{_.name}}
                 </a-menu-item>
               </a-sub-menu>
-              <a-menu-item v-if="!item.children"  :key="item.path"  @click="changeRoute(item)" >
-                <user-outlined />
-                <span>{{item.name}}</span>
-              </a-menu-item>
             </template>
           </a-menu>
         </a-layout-sider>
@@ -54,6 +55,8 @@ import { MenuFoldOutlined, MenuUnfoldOutlined, UserOutlined } from '@ant-design/
 const emitter = useEmitter()
 const appRouter = useAppRouter()
 
+console.log(appRouter)
+
 const onCollapse = () => {}
 const onBreakpoint = () => {}
 
@@ -63,8 +66,6 @@ const selectedKeys2 = ref<string[]>([appRouter.router.sider!.selectPath])
 const openKeys = ref<string[]>(appRouter.router.sider!.openKeys)
 
 emitter.on(Emitter.NAVBAR, () => {
-  console.log('[appRouter.router.sider!.selectPath]:', [appRouter.router.sider!.selectPath])
-
   selectedKeys2.value = [appRouter.router.sider!.selectPath]
   openKeys.value = appRouter.router.sider!.openKeys
 })
@@ -73,6 +74,26 @@ const changeRoute = (route: Router.RoutesProps) => {
   RootRouter.push(route.path)
 }
 
+const hasOneShowingChild = (children = [], parent) => {
+  const showingChildren = children.filter(item => {
+    if (item.hidden) {
+      return false
+    } else {
+      return true
+    }
+  })
+
+  if (showingChildren.length === 1) {
+    return true
+  }
+
+  if (showingChildren.length === 0) {
+    return true
+  }
+
+  return false
+}
+
 </script>
 
 <style lang="less" scoped >

+ 1 - 1
src/pages/Iot/model/index.vue

@@ -31,7 +31,7 @@
       <template #bodyCell="{ column, record }">
           <template v-if="column.key === 'action'">
             <a-space>
-              <a href="#" @click="goDetailPage(record.id)" >查看</a>
+              <a @click="goDetailPage(record.id)" >查看</a>
                 <a-popconfirm
                   title="确实要删除吗?"
                   ok-text="确定"

+ 2 - 1
src/router/before.ts

@@ -1,6 +1,7 @@
-import { useTitle } from '@/hooks/bom'
+
 import router from './index'
 
 router.beforeEach((to, from, next) => {
+  console.log('触发了路由守卫')
   next()
 })

+ 15 - 8
src/router/index.ts

@@ -16,14 +16,22 @@ const routes: Array<ROUTER.RoutesProps> = [
       {
         path: '/product',
         name: '产品',
-        component: () => import('@/pages/iot/model/index.vue')
-      },
-      {
-        path: '/product/detail',
-        name: '产品详情',
-        hidden: true,
-        component: () => import('@/pages/iot/model/detail.vue')
+        redirect: '/product/index',
+        children: [
+          {
+            path: '/product/index',
+            name: '产品',
+            component: () => import('@/pages/iot/model/index.vue')
+          },
+          {
+            path: '/product/detail',
+            name: '产品详情',
+            hidden: true,
+            component: () => import('@/pages/iot/model/detail.vue')
+          }
+        ]
       }
+
       // {
       //   path: '/deviceAccess',
       //   name: '地址展示',
@@ -42,7 +50,6 @@ const routes: Array<ROUTER.RoutesProps> = [
     ]
   }
 ]
-
 const router = createRouter({
   history: createWebHistory(process.env.BASE_URL),
   routes

+ 0 - 1
src/service/request.ts

@@ -12,7 +12,6 @@ const instance = axios.create({
  * @returns `catchErr` 函数返回一个被拒绝的 Promise,并传递了 `error` 参数作为拒绝的原因。
  */
 const catchErr = (response: AxiosResponse) => {
-  console.log('发生了错误:', response)
   const { data } = response
   if (data.code === 500) {
     message.error(data.msg)

+ 4 - 0
src/store/router.ts

@@ -35,6 +35,8 @@ export const useAppRouter = defineStore(ConstantStore.ROUTER, () => {
     defaultValue: initAppRouterState
   })
 
+  console.log(RootRouter)
+
   const siderRoutes = computed(() => RootRouter.getRoutes().find(item => item.path === appRouter.navbar!.selectPath)?.children)
 
   const initAppRouter = () => {
@@ -60,6 +62,8 @@ export const useAppRouter = defineStore(ConstantStore.ROUTER, () => {
   watch(
     () => RootRouter.currentRoute.value.path,
     () => {
+      console.log('当前路由改变')
+
       appRouter.sider = {
         route: RootRouter.getRoutes().find(item => item.path === appRouter.navbar!.selectPath)?.children as ROUTER.RoutesProps[],
         selectPath: RootRouter.currentRoute.value.path,

+ 5 - 0
yarn.lock

@@ -5489,6 +5489,11 @@ pascal-case@^3.1.2:
     no-case "^3.0.4"
     tslib "^2.0.3"
 
+path-browserify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
+  integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==
+
 path-exists@^4.0.0:
   version "4.0.0"
   resolved "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"