index.vue 7.6 KB
<script lang="ts" setup name="Tabbar">
import { ref } from "vue";
import { useRouter } from "vue-router";
import useUserStore from "@/store/modules/user";
import useKeepAliveStore from '@/store/modules/keepAlive'
import { ElMessageBox, ElMessage } from "element-plus";

const router = useRouter();
const route = useRoute();
const userStore = useUserStore();
const keepAliveStore = useKeepAliveStore();
const tabbarList: any = ref([]);
const tabbarActive = ref("");
const visibleTabs = ref([])
watch(
  () => router.currentRoute.value,
  (newRouter: any) => {
    const pathArr = newRouter.fullPath.split('/')
    const combPath = pathArr[1] || 'app-scenes'
    const toPath = pathArr[2]
    const routerLength = pathArr.length
    const jionPath = pathArr.slice(0,3).join("/")
    let list: any = userStore.tabbar;
    let pathIndex = ref(-1)
    const isExist = list.filter((tab: any,index) => {
      if(tab.fullPath.includes(jionPath)) {
        pathIndex.value = index
      }
      return tab.fullPath === newRouter.fullPath
    });  
    if(isExist.length == 0) {
      if( pathIndex.value!=-1 && routerLength > 3 ) {
       list.splice(pathIndex.value+1,0,newRouter)
      } else {
        let pathIndex = -1
        const option = list.find((item,index)=>{
          pathIndex = index
          return item.path===newRouter.path
        })
        if(option){
          list.splice(pathIndex,1,newRouter);
        } else {
          list.push(newRouter)
        }
        
      }
    }
   // isExist.length == 0 && list.push(newRouter);
    list.map(item => {
      if (combPath == 'app-scenes') {
        item.visible = item.fullPath == '/'
      } else {
        if (item.fullPath.split('/')?.[1] != combPath) {
          item.visible = false
        } else {
          item.visible = true
        }
      }
    })
    tabbarList.value = list;
    tabbarActive.value = newRouter.fullPath;
    userStore.setTabbar(tabbarList.value);
    userStore.setActiveTabbar(combPath, newRouter.fullPath);
    nextTick(() => {
      setTabVisible()
    })
  },
  { immediate: true }
);
const changeTab = (pane: any, ev: any) => {
  const tabIndex = Number(pane.index);
  const paneData: any = tabbarList.value[tabIndex];
  router.push({
    name: paneData.name,
    query: paneData.query
  });
  const combPath = paneData.fullPath.split('/')[1] || 'app-scenes'
  userStore.setActiveTabbar(combPath, paneData.fullPath);
};
const removeTab = (targetName) => {
  const tabs = tabbarList.value.filter(item => item.visible ?? true);
  const setTabs = (activeTab) => {
    tabbarActive.value = activeName;
    tabbarList.value = tabbarList.value.filter((tab) => tab.fullPath !== targetName);
    userStore.setTabbar(tabbarList.value);
    const combPath = activeName.split('/')[1]
    userStore.setActiveTabbar(combPath, activeName);
    let tabIndex = visibleTabs.value.findIndex(v => v === targetName)
    if (tabIndex > -1) {
      visibleTabs.value.splice(tabIndex, 1);
      if (activeTab && router.currentRoute.value.fullPath != targetName) {
        keepAliveStore.remove(activeTab.meta.reuse ? activeTab.fullPath : activeTab.matched.at(-1)?.components?.default?.name)
      } 
    }
    nextTick(() => {
      nextTab.name && router.push({ name: nextTab.name, query: nextTab.query });
      setTabVisible()
    });
  }

  let activeName = tabbarActive.value;
  let nextTab: any = {};
  if (tabbarActive.value === targetName) {
    tabs.forEach((tab, index) => {
      if (tab.fullPath === targetName) {
        nextTab = tabs[index + 1] || tabs[index - 1];
        if (nextTab) {
          activeName = nextTab.fullPath;
        }
      }
    });
  }

  let activeTab: any = tabs.find(t => t.fullPath === targetName);
  if (activeTab.meta.editPage) {
    ElMessageBox.confirm(
      "当前页面尚未保存,确定关闭吗?",
      "提示",
      {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }
    )
      .then(() => {
        setTabs(activeTab)
      })
      .catch(() => {
        ElMessage({
          type: "info",
          message: "已取消",
        });
      });
  } else {
    setTabs(activeTab)
  }
};

const setTabVisible = () => {
  const tabpanes: any = document.querySelectorAll('.tabbar-container .el-tabs__item')
  let list: any = []
  tabpanes.forEach((tab, i) => {
    const visible = tabbarList.value[i].visible ?? true
    if (!visible) {
      tab.style.display = 'none'
    } else {
      tab.style.display = 'inherit'
      list.push(tabbarList.value[i].fullPath)
    }
  })
  visibleTabs.value = list
}

onMounted(() => {

})
</script>
<template>
  <div class="tabbar-container">
    <el-tabs v-model="tabbarActive" type="card" @tab-click="changeTab" @tab-remove="removeTab">
      <el-tab-pane v-for="(item, index) in tabbarList" :key="item.fullPath + '_' + index" :name="item.fullPath"
        :closable="visibleTabs.length > 1">
        <template #label v-if="item.isHomePage">
          <span class="custom-tabs-label">
            <el-icon>
              <svg-icon name="bar-home" />
            </el-icon>
            <ellipsis-tooltip :content="item.meta?.title" class-name="w100f"
                  :refName="'tooltipOver' + item.meta?.title"></ellipsis-tooltip>
          </span>
        </template>
        <template #label v-else>
          <span class="custom-tabs-label">
            <ellipsis-tooltip :content="item.meta?.title" class-name="w100f"
                  :refName="'tooltipOver' + item.meta?.title"></ellipsis-tooltip>
          </span>
        </template>
      </el-tab-pane>
    </el-tabs>
  </div>
</template>
<style lang="scss" scoped>
.tabbar-container {
  width: calc(100% - var(--g-main-sidebar-actual-width) - var(--g-sub-sidebar-actual-width));
  position: absolute;
  top: var(--g-header-height);
  background-color: var(--el-bg-color);

  :deep(.el-tabs) {
    height: var(--g-tapbar-height);
    // border-bottom: 1px solid #e5e5e5;

    .el-tabs__header {
      height: 100%;
      margin-bottom: 0;
      border-bottom: none;

      .el-tabs__nav-wrap {
        padding-top: 4px;
        padding-left: 20px;
      }

      .el-tabs__nav {
        border: none;

        .el-tabs__active-bar {
          background-color: transparent;
        }
      }

      .el-tabs__nav-next,
      .el-tabs__nav-prev {
        height: 30px;
        display: flex;
        justify-content: center;
        flex-direction: column;
        align-items: center;
      }

      .el-tabs__item {
        height: calc(var(--g-tapbar-height) - 4px);
        border: none;
        color: var(--el-text-color-regular);
        font-size: 1rem;
        padding: 0 10px;

        .custom-tabs-label {
          max-width: 280px;
          .el-icon {
            color: #999;

            svg {
              width: 14px;
              height: 14px;
            }
          }
        }

        // &::after {
        //   content: "";
        //   width: calc(100% - 40px);
        //   height: 2px;
        //   background-color: transparent;
        //   position: absolute;
        //   left: 20px;
        //   bottom: 0;
        //   // transform: translateX(-50%);
        // }

        &.is-active {
          // border-bottom-color: var(--el-color-primary);
          background: #fff;
          border-radius: 4px 4px 0 0;
          color: var(--el-color-primary);
          
          .custom-tabs-label {
            max-width: 280px;
            .el-icon {
              color: var(--el-color-primary);
            }
          }

          // &::after {
          //   // background-color: var(--el-color-primary);
          // }
        }

        &:hover {
          .is-icon-close {
            // width: 14px;
          }
        }
      }
    }
  }
}
</style>