前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我攻克的技术难题 - BuildAdmin14:关闭tab,居然用了vue-router的重定向

我攻克的技术难题 - BuildAdmin14:关闭tab,居然用了vue-router的重定向

原创
作者头像
叫我阿柒啊
修改2024-02-14 08:56:45
2621
修改2024-02-14 08:56:45
举报

前言

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

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

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

代码语言:typescript
复制
case 'close':
    closeTab(menu)
    break
case 'closeOther':
    closeOtherTab(menu)
    break
case 'closeAll':
    closeAllTab(menu)
    break

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

关闭当前

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

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

onTabViewClose事件

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

代码语言:typescript
复制
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事件。

代码语言:typescript
复制
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是控制台。

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

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

代码语言:typescript
复制
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。

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

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

代码语言:typescript
复制
const firstRoute = getFirstRoute(navTabs.state.tabsViewRoutes)
router.push(firstRoute.path)

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

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

重定向路由

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

代码语言:typescript
复制
{
    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组件。

匹配不到的路由

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

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

如图所示:

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

loading

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

代码语言:html
复制
<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才是核心。

代码语言:typescript
复制
if (navTabs.state.tabsViewRoutes) {
    let firstRoute = getFirstRoute(navTabs.state.tabsViewRoutes)
    if (firstRoute) router.push(firstRoute.path)
}

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

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

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

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

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

结语

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

我正在参与2024腾讯技术创作特训营第五期有奖征文,快来和我瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 关闭当前
  • onTabViewClose事件
  • 最后的tab
  • 重定向路由
    • 匹配不到的路由
      • loading
      • 结语
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档