Ver código fonte

完成GlobalTabs组件

tongshangming 3 anos atrás
pai
commit
37f19046a1
4 arquivos alterados com 149 adições e 52 exclusões
  1. 6 1
      src/assets/main.css
  2. 141 49
      src/components/GlobalTabs.vue
  3. 1 1
      src/config/defaultSetting.ts
  4. 1 1
      src/stores/user.ts

+ 6 - 1
src/assets/main.css

@@ -4,6 +4,11 @@
   height: 100vh;
 }
 
-.el-card{
+a {
+  text-decoration: none;
+  transition: 0.4s;
+}
+
+.el-card {
   border: none !important;
 }

+ 141 - 49
src/components/GlobalTabs.vue

@@ -4,24 +4,65 @@ import type { RouteLocationNormalizedLoaded } from 'vue-router'
 import config from '@/config/defaultSetting'
 import { useRouterStore } from '@/stores/router'
 
+interface Tab {
+  name: string
+  fullPath: string
+  params: object
+  query: object
+  title: string
+}
+
 const router = useRouter()
 const route = useRoute()
 const routerStore = useRouterStore()
 
-const tabs = ref<any[]>([])
-const activeValue = ref(route.fullPath)
-const contextMenuVisible = ref(false)
-
+const routeToTab = (route: any) => {
+  return {
+    name: route.name,
+    fullPath: route.fullPath || route.path,
+    params: route.params,
+    query: route.query,
+    title: route.meta?.title
+  }
+}
 const getHomeRoute = (route: []) => {
   return route.find((item: any) => {
     if (item.children) {
       getHomeRoute(item.children)
     } else {
-      return item.name === config.homeRoute
+      return item.name === config.homeRouteName
     }
   })
 }
 
+const tabs = useStorage<any[]>('globalTabs', [routeToTab(getHomeRoute(routerStore.menuRouter))], sessionStorage)
+const activeValue = ref(route.fullPath)
+const activeIndex = ref(0)
+
+const findActiveIndex = (fullPath: string | number) => {
+  return tabs.value.findIndex(item => item.fullPath === fullPath)
+}
+
+const setTab = (tab: RouteLocationNormalizedLoaded) => {
+  activeValue.value = tab.fullPath
+  activeIndex.value = findActiveIndex(tab.fullPath)
+
+  if (tab.name === 'login' || tabs.value.find(item => item.fullPath === tab.fullPath)) {
+    return
+  }
+  tabs.value.push(routeToTab(tab))
+}
+const changeTab = (name: TabPanelName) => {
+  activeIndex.value = findActiveIndex(name)
+  router.push(tabs.value.find(item => item.fullPath === name))
+}
+const removeTab = (name: TabPanelName) => {
+  const index = findActiveIndex(name)
+  activeIndex.value = index < tabs.value.length - 1 ? index + 1 : index - 1
+  router.push(tabs.value[activeIndex.value])
+  tabs.value.splice(index, 1)
+}
+
 watch(
   () => route,
   to => {
@@ -31,47 +72,66 @@ watch(
     deep: true
   }
 )
-watch(
-  tabs,
-  () => {
-    sessionStorage.setItem('globalTabs', JSON.stringify(tabs.value))
-  },
-  {
-    deep: true
-  }
-)
-const setTab = (tab: RouteLocationNormalizedLoaded) => {
-  activeValue.value = tab.fullPath
 
-  if (tab.name === 'login' || tabs.value.find(item => item.fullPath === tab.fullPath)) {
-    return
+const contextMenuVisible = ref(false)
+const left = ref(0)
+const top = ref(0)
+const contextMenuIndex = ref(0)
+const contextMenuItem = computed(() => tabs.value[contextMenuIndex.value]) as any
+
+const findContextMenuItemIndex = (fullPath: string) => tabs.value.findIndex(item => item.fullPath === fullPath)
+
+const openContextMenu = (e: any) => {
+  const id = e.target?.offsetParent?.id || e.target?.id
+  if (id) {
+    const fullPath = id.split('-')[1]
+    contextMenuIndex.value = findContextMenuItemIndex(fullPath)
+    left.value = e.clientX + 1
+    top.value = e.clientY + 1
+    contextMenuVisible.value = true
   }
+}
+const closeContextMenu = () => {
+  contextMenuVisible.value = false
+}
 
-  tabs.value.push(routeToTab(tab))
+const closeAll = () => {
+  router.push(tabs.value[0])
+  tabs.value.splice(1)
+  closeContextMenu()
 }
-const routeToTab = (route: any) => {
-  return {
-    name: route.name,
-    fullPath: route.fullPath,
-    params: route.params,
-    query: route.query,
-    title: route.meta.title
+const closeLeft = () => {
+  if (activeIndex.value < contextMenuIndex.value) {
+    router.push(contextMenuItem)
   }
+  tabs.value.splice(1, contextMenuIndex.value - 1)
+  closeContextMenu()
 }
-tabs.value.push(routeToTab(getHomeRoute(routerStore.menuRouter)))
-console.log(routeToTab(getHomeRoute(routerStore.menuRouter)))
-const initTabs = () => {
-  tabs.value = JSON.parse(sessionStorage.getItem('globalTabs') || '[]')
-  activeValue.value = window.sessionStorage.getItem('activeValue') || route.fullPath
+const closeRight = () => {
+  if (activeIndex.value > contextMenuIndex.value) {
+    router.push(contextMenuItem)
+  }
+  tabs.value.splice(contextMenuIndex.value + 1)
+  closeContextMenu()
 }
-initTabs()
 
-const changeTab = (name: TabPanelName) => {
-  router.push(tabs.value.find(item => item.fullPath === name))
-  sessionStorage.setItem('activeValue', name as string)
+const closeOther = () => {
+  router.push(contextMenuItem)
+  if (contextMenuIndex.value) {
+    tabs.value = [tabs.value[0], contextMenuItem]
+  } else {
+    tabs.value = [tabs.value[0]]
+  }
+  contextMenuVisible.value = false
 }
-const removeTab = () => {}
-const openContextMenu = (event: any) => {}
+
+watch(contextMenuVisible, val => {
+  if (val) {
+    document.body.addEventListener('click', closeContextMenu)
+  } else {
+    document.body.removeEventListener('click', closeContextMenu)
+  }
+})
 </script>
 
 <template>
@@ -80,26 +140,32 @@ const openContextMenu = (event: any) => {}
       v-model="activeValue"
       :closable="!(tabs.length === 1)"
       type="card"
-      @contextmenu.prevent="openContextMenu($event)"
       @tab-change="changeTab"
       @tab-remove="removeTab"
+      @contextmenu.prevent="openContextMenu($event)"
     >
-      <el-tab-pane v-for="item in tabs" :key="item.name" :label="item.title" :name="item.fullPath" :tab="item">
+      <el-tab-pane
+        v-for="item in tabs"
+        :key="item.name"
+        :label="item.title"
+        :name="item.fullPath"
+        :tab="item"
+        :closable="item.name !== config.homeRouteName"
+      >
+        <template #label>
+          <span>{{ item.title }}</span>
+        </template>
       </el-tab-pane>
     </el-tabs>
   </div>
 
   <!--自定义右键菜单html代码-->
-  <!-- <ul
-      v-show="contextMenuVisible"
-      :style="{ left: left + 'px', top: top + 'px' }"
-      class="contextmenu"
-    >
-      <li @click="closeAll">关闭所有</li>
-      <li @click="closeLeft">关闭左侧</li>
-      <li @click="closeRight">关闭右侧</li>
-      <li @click="closeOther">关闭其他</li>
-    </ul> -->
+  <ul v-show="contextMenuVisible" :style="{ left: left + 'px', top: top + 'px' }" class="contextmenu">
+    <li @click="closeAll">关闭所有</li>
+    <li @click="closeLeft">关闭左侧</li>
+    <li @click="closeRight">关闭右侧</li>
+    <li @click="closeOther">关闭其他</li>
+  </ul>
 </template>
 
 <style lang="scss" scoped>
@@ -110,4 +176,30 @@ const openContextMenu = (event: any) => {}
   border-top: none !important;
   border-radius: 0 !important;
 }
+:deep(.el-tabs__item.is-active) {
+  background-color: var(--el-color-primary-light-9);
+  border-bottom-color: var(--el-border-color) !important;
+}
+.contextmenu {
+  position: fixed;
+  width: 100px;
+  margin: 0;
+  border-radius: 4px;
+  background: var(--el-bg-color-overlay);
+  border: 1px solid var(--el-border-color-light);
+  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+  z-index: 3000;
+  list-style-type: none;
+  padding: 0;
+
+  li {
+    margin: 0;
+    padding: 7px 16px;
+    cursor: pointer;
+
+    &:hover {
+      background: #f2f2f2;
+    }
+  }
+}
 </style>

+ 1 - 1
src/config/defaultSetting.ts

@@ -1,6 +1,6 @@
 export default {
   title: '方是科技管理系统',
   logo: '/logo.png',
-  homeRoute: 'home',
+  homeRouteName: 'home',
   themeColor: '#1890ff'
 }

+ 1 - 1
src/stores/user.ts

@@ -25,7 +25,7 @@ export const useUserStore = defineStore({
       localStorage.removeItem('token')
       sessionStorage.removeItem('globalTabs')
       this.$reset()
-      console.log(router.currentRoute)
+      console.log(router)
       router.push({ path: '/login', query: { redirect: router.currentRoute.value.fullPath } })
     }
   }