navegación de varias páginas vue3

<template>
  <div class="px-10px bg-white flex ">
    <a-tabs v-model:activeKey="tabsMenuValue" @tabClick="tabClick" class="flex-1">
      <a-tab-pane v-for="item in tabsMenuList" :key="item.path">
        <template #tab>
          <span>
            <dashboard-outlined />
            {
    
    {
    
     item.title }}
            <close-outlined v-if="item.close" @click.stop="tabRemove(item)" class="ml-4px" />
          </span>
        </template>
      </a-tab-pane>
    </a-tabs>
    <div style="width: 80px;" class="flex align-items-center justify-content-center ">
      <a-dropdown>
        <a-button type="primary" size="small">
          {
    
    {
    
     $t("tabs.more") }}
          <DownOutlined />
        </a-button>
        <template #overlay>
          <a-menu>
            <a-menu-item>
              <a href="javascript:;" @click="closeCurrent">{
    
    {
    
     $t("tabs.closeCurrent") }}</a>
            </a-menu-item>
            <a-menu-item>
              <a href="javascript:;" @click="closeOtherTab">{
    
    {
    
     $t("tabs.closeOther") }}</a>
            </a-menu-item>
          </a-menu>
        </template>
      </a-dropdown>
    </div>
  </div>
</template>
<script  lang='ts' setup>
import Sortable from "sortablejs";
import {
    
     onMounted, ref, computed, watch } from 'vue'
import {
    
     useRoute, useRouter } from 'vue-router';
import {
    
     useTabsStore } from '@/store/useTabsStore'
import {
    
     useKeepAliveStore } from '@/store/keepAlive'
import {
    
     DashboardOutlined, CloseOutlined, DownOutlined } from '@ant-design/icons-vue'
const route = useRoute()
const router = useRouter()
const tabsMenuValue = ref(route.fullPath);
const tabStore = useTabsStore();
const keepAliveStore = useKeepAliveStore();
const tabsMenuList = computed(() => tabStore.tabsMenuList);

// 监听路由的变化(防止浏览器后退/前进不变化 tabsMenuValue)
watch(
  () => route.fullPath,
  () => {
    
    
    if (route.meta.isFull) return;
    tabsMenuValue.value = route.fullPath;
    const tabsParams = {
    
    
      icon: route.meta.icon as string,
      title: route.meta.title as string,
      path: route.fullPath,
      name: route.name as string,
      close: !route.meta.isAffix
    };
    tabStore.addTabs(tabsParams);
    route.meta.isKeepAlive && keepAliveStore.addKeepAliveName(route.name as string);
  },
  {
    
     immediate: true }
);
onMounted(() => {
    
    
  tabsDrop()
})

const tabClick = (path: string) => {
    
    
  console.log(path)
  router.push(path);
}
// Remove Tab
const tabRemove = (item: any) => {
    
    
  console.log('item', item)
  const {
    
     path }: {
    
     path: string } = item
  const name = tabStore.tabsMenuList.filter(item => item.path == path)[0].name || "";
  keepAliveStore.removeKeepAliveName(name);
  tabStore.removeTabs(path as string, path == route.fullPath);
};

function closeCurrent() {
    
    
  console.log(route)
  if (route.meta.isAffix) return
  tabStore.removeTabs(route.fullPath)
  keepAliveStore.removeKeepAliveName(route.name as string)
}
function closeOtherTab() {
    
    

  tabStore.closeMultipleTab(route.fullPath)
  keepAliveStore.setKeepAliveName([route.name] as string[])
}

// tabs 拖拽排序
const tabsDrop = () => {
    
    
  Sortable.create(document.querySelector(".ant-tabs-nav-list") as HTMLElement, {
    
    
    draggable: ".ant-tabs-tab",
    animation: 300,
    // onEnd({ newIndex, oldIndex }:{ newIndex: number, oldIndex: number }) {
    
    
    //   const tabsList = [...tabStore.tabsMenuList];
    //   const currRow = tabsList.splice(oldIndex as number, 1)[0];
    //   tabsList.splice(newIndex as number, 0, currRow);
    //   tabStore.setTabs(tabsList);
    // }
  });
};
</script>
<style lang="scss" scoped>
:deep(.ant-tabs-nav) {
    
    
  margin-bottom: 0 !important;
}
</style>
import router from "@/router";
import {
    
     defineStore } from 'pinia'
import {
    
     TabsMenuProps, TabsState } from './interface/index'
export const useTabsStore = defineStore('useTabsStore', {
    
    
  state: (): TabsState => ({
    
    
    tabsMenuList: []
  }),
  actions: {
    
    
    // Add Tabs
    async addTabs(tabItem: TabsMenuProps) {
    
    
      if (this.tabsMenuList.every(item => item.path !== tabItem.path)) {
    
    
        this.tabsMenuList.push(tabItem);
      }
    },
    // Remove Tabs
    async removeTabs(tabPath: string, isCurrent = true) {
    
    
      const tabsMenuList = this.tabsMenuList;
      if (isCurrent) {
    
    
        tabsMenuList.forEach((item, index) => {
    
    
          if (item.path !== tabPath) return;
          const nextTab = tabsMenuList[index + 1] || tabsMenuList[index - 1];
          if (!nextTab) return;
          router.push(nextTab.path);
        });
      }
      this.tabsMenuList = tabsMenuList.filter(item => item.path !== tabPath);
    },
    // Close MultipleTab
    async closeMultipleTab(tabsMenuValue?: string) {
    
    
      this.tabsMenuList = this.tabsMenuList.filter(item => {
    
    
        return item.path === tabsMenuValue || !item.close;
      });
    },
    // Set Tabs
    async setTabs(tabsMenuList: TabsMenuProps[]) {
    
    
      this.tabsMenuList = tabsMenuList;
    },
    // Set Tabs Title
    async setTabsTitle(title: string) {
    
    
      const nowFullPath = location.hash.substring(1);
      this.tabsMenuList.forEach(item => {
    
    
        if (item.path == nowFullPath) item.title = title;
      });
    }
  },
})

Supongo que te gusta

Origin blog.csdn.net/qq_42975676/article/details/130993912
Recomendado
Clasificación