自学前端14:vue-router重定向,是如何关闭tab标签页的

社区Vue前端框架

前言

上一篇讲了重新加载标签功能的实现,主要是利用了mitt事件总线库。本篇文章就接着实现关闭标签的功能。

picture.image

在关闭tab的功能中,一共包含了三种情况:关闭当前标签、关闭其他标签,关闭全部标签,我们就看看如何逐一实现。

在tabs.vue的onContextmenuItem方法中,对三种标签的关闭做了以下的逻辑处理。

case 'close':
    closeTab(menu)
    break
case 'closeOther':
    closeOtherTab(menu)
    break
case 'closeAll':
    closeAllTab(menu)
    break

对当前tab的关闭,定义了一个closeTab方法,closeOtherTab关闭其他标签,closeAllTab是关闭所有标签。我们首先来closeTab是如何实现关闭当前tab的。

关闭当前

记得我们之前在实现tab的关闭时,定义了一个closeTab,这里就是使用那个方法。

picture.image

具体实现思路可以跳转文章BuildAdmin09:tab的关闭,让滑动块何去何从查看。

onTabViewClose事件

但这里与之前相比,添加了一行代码,调用了mitt的emit向main.vue发送了关闭事件,用来在main中删除keepAlive缓存的组件。

const closeTab = (route: RouteLocationNormalized) => {
    navTabs.closeTab(route)
    proxy.eventBus.emit('onTabViewClose', route)
    if (navTabs.state.activeRoute?.path === route.path) {
        toLastTab()
    } else {
        nextTick(() => {
            if (navTabs.state.activeRoute != null) {
                navTabs.setActiveRoute(navTabs.state.activeRoute)
            }
            const div = tabsRefs.value[navTabs.state.activeIndex]
            selectNavTab(div)
        })
    }
}

因为在上一篇BuildAdmin13:区区重新加载,vue居然用了mitt事件总线库中,main使用keep-alive对所有tab组件实例进行了缓存。所以在关闭的时候要将keepAliveComponentNameList中对应的缓存删除掉。在main.vue中接收mitt的onTabViewClose事件。

proxy.eventBus.on('onTabViewClose', (menu: RouteLocationNormalized) => {
    state.keepAliveComponentNameList = state.keepAliveComponentNameList.filter((name: string) => menu.meta.keepalive !== name)
})

与上一篇实现重新加载的onTabViewRefresh事件一样,利用filter过滤掉与tab匹配的组件实例,实现删除。

最后的tab

除了复用之前tab关闭的方法之外,还有一种情况需要考虑。虽然当tab只剩下最后一个时,关闭按钮就没了。但在弹出框里,最后一个tab仍然可以关闭,只是在关闭之后需要自动跳转到第一个tab,即之前多次用到的firstRoute

在BuildAdmin中tabs的实现中,默认的firstRoute是控制台。

picture.image

也就是说,当关闭最后一个tab后,就要打开(跳转)控制台的tab(路由)。

picture.image

BuildAdmin09:tab的关闭,让滑动块何去何从的clostTab方法中,在实现关闭tab后,调用toLastTab方法打开新的tab页。

const toLastTab = () => {
    const lastTab = navTabs.state.tabsView.slice(-1)[0]
    if (lastTab) {
        router.push(lastTab.path)
    } else {
        router.push('/admin')
    }
}

因为当只剩下一个tab是,这个tab的关闭按钮就会隐藏,所以无论如何,tabsView都会有至少一个tab,即lastTab一定为true。关闭当前tab之后,机制就是滑动块跳转到导航栏中的最后一个tab。

picture.image

当最后一个tab被弹出框的关闭当前关闭之后,tabsView就一个tab也没有了,所以lastTab为false,这时候就会跳转到 /admin这个路由,当然,你可以跳转到你想跳转的任何路由,或者这里直接route.push("/admin/dashboard"),直接跳转到控制台。

万一dashboard不是第一个路由怎么办,那么我们也可以这样写。

const firstRoute = getFirstRoute(navTabs.state.tabsViewRoutes)
router.push(firstRoute.path)

这样就直接实现了关闭最后一个tab之后,跳转默认tab的功能。

但在BuildAdmin中,是跳转的admin路由,然后定义了一个Loading路由进行重定向到firstRoute(控制台)。

重定向路由

在router的static.ts中,新增一个匹配/admin的路由。

{
    path: '/admin:path(.*)*',
    redirect: (to) => {
        return {
            name: 'adminMainLoading',
            params: {
                to: JSON.stringify({
                    path: to.path,
                    query: to.query,
                }),
            },
        }
    },
}

const adminBaseRoute: RouteRecordRaw = {
    path: '/loading/:to?',
    name: 'adminMainLoading',
    component: () => import('@/layouts/common/components/loading.vue'),
    meta: {
        title: pageTitle('Loading'),
    },
}

以/admin开头的,且在router中匹配不到的路由,会被redirect(重定向)到adminMainLoading路由中,然后加载loading组件。

picture.image

匹配不到的路由

在BuildAdmin什么时候匹配不到路由呢?两种情况:

  1. 未定义的,例如/admin肯定是没有定义在router中的
  2. url的路径中包含了route.path,在刷新浏览器时,路由动态加载还没加载到router中,这时候就是匹配不上。这个情况在BuildAdmin05:如何玩转Vue路由动态加载 的路由bug中提到了。

如图所示:

picture.image

这种404的情况路由还没加载完成,在router中匹配不到路由导致的。我们从url中可以看到路由也是以admin开头的,所以也会重定向到/loading路由,看看loading.vue中如何实现的。

loading

loading.vue使用了ElementPlus的loading组件实现的。

<template>
  <div>
      <div
          v-loading="true"
          element-loading-background="var(--ba-bg-color-overlay)"
          element-loading-text="Loading..."
          class="default-main ba-main-loading"
      ></div>
      <div v-if="state.showReload" class="loading-footer">
          <el-button @click="refresh" type="warning"></el-button>
      </div>
  </div>
</template>

在setup中定义的router跳转firstRoute才是核心。

if (navTabs.state.tabsViewRoutes) {
    let firstRoute = getFirstRoute(navTabs.state.tabsViewRoutes)
    if (firstRoute) router.push(firstRoute.path)
}

这也就意味着只要加载loading组件,就会调用上面的js跳转firstRoute。当我们再次刷新浏览器的时候,就不会跳转到404,而是重定向到控制台。

picture.image

接着我们看看,通过弹出框关闭当前关闭最后一个tab,跳转/admin路由时,是否也会重定向到控制台。

picture.image

如图所示,关闭最后一个tab的时候,重定向到了控制台。也可以看到重定向的过程中url有变化,那就是重定向时传递的参数。这里一共触发了三次路由的跳转: /admin -> /loading -> /admin/dashboard

所以,一个重定向路由,解决了404和关闭当前两个问题。

不知道大家发现了一个问题没有,虽然触发了loading.vue组件,但是在页面上没有显示。这个就和BuildAdmin06:进度条和Loading页面的实现中实现的Loading页面就有关系了,在刷新页面触发路由时,会展示这个Loading页面,因为z-index: 9990的设置,图层在最上方会优先显示。

结语

这就是关闭当前标签功能实现的整个流程,用到了很多之前写的知识点,意味着在前端的开发中,各个部分是紧密相连的,需要有一个全局的设计和认知。同时,对vue生态中各部分的知识也要牢牢掌握,例如本篇中提及的vue-router的redirect、vue的keep-alive等。

0
0
0
0
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论