RouterLink组件实现标签栏,路由多次跳转

34 阅读4分钟

背景

最近在写后台项目时,使用RouterLink组件去实现如下图所示的顶部标签栏时,遇到了跳转失败的情况,因此记录一笔。 image.png

问题复现

具体实现标签栏的代码如下:

<el-scrollbar ref="elScrollbar">
    <div class="tag-view-container">
      <router-link
        class="tag-view__item"
        v-for="(item, index) in tagViewList"
        :key="index"
        :to="item.path"
        @click="toScrollCurrentTagView()"
      >
        <div class="tag_view__body">
          <span class="tag_view_title">{{ item.meta.title }}</span>
          <el-icon
            v-if="isAffix(item)"
            class="icon-close"
            @click="handleCloseTagView(item)"
          >
            <Close />
          </el-icon>
        </div>
      </router-link>
    </div>
</el-scrollbar>

这里可以看到,我通过在tag_view__body外面包裹一层RouteLink组件,实现点击跳转到相应的路由。标签栏的基本操作主要新增、删除.具体实现,我也贴出代码供大家参考:

// 新增标签的实现
import { useTagViewsStore } from '@/store/modules/tagViews'

watch(route, () => {
  tagViewsStore.addTagView(Object.assign({}, route))
  setCurrentTagView() // 用来设置当前路由激活状态
})

新增标签我这里采用的是通过watch监听路由的变化,如果发送变化就调用pinia中的设置的方法将当前路由加入tagViewList(标签集合)中。这里需要注意的是对于route需要进行一次拷贝,否则你会发现,每次添加新的标签到tagViewList集合中时,标签集合中的所有数据都和最后一次添加的数据一样,主要原因是存储的是引用类型的地址,如果没有进行拷贝的话,每次传入的都是同一个对象的地址,导致最后获取tagViewList中的元素都是和最后一次添加的相同。至此,新增操作没有太大的问题。

先贴出删除标签的操作代码:

// 关闭标签操作
function handleCloseTagView(tagView, event) {
  event.stopPropagation()
  // findTagViewIndex() 返回当前关闭标签在tagViewList中的index
  const tagViewIndex = findTagViewIndex(tagViewList.value, tagView)
  const lastIndex = tagViewIndex - 1
  // isActive() 方法是用来判断当前关闭是否是已激活的标签,如果是激活的标签需要指定下一个激活的标签,如果不是则直接删除
  if (isActive(tagView)) {
    router.push({ path: tagViewList.value[lastIndex].fullPath })
  }
  tagViewsStore.deleteTagView(tagView)
}

写到这里,我以为删除部分已经处理完了,easy~ 可是理想很丰满,现实却很骨感。页面实现的效果如下所示:

image.png 这里我点击了关闭角色管理标签,可以看到角色标签并没有关闭。正确的关闭执行情况应该是:角色管理标签关闭,用户管理激活,路由跳转到用户管理。这里我在全局前置路由守卫中打印了回调函数中的tofrom,发现路由从角色管理调转到了用户管理,但是又从用户管理跳回了角色管理(由于在前面标签新增那里使用watch监听了路由的变化,因此当路由从用户管理跳回角色管理的时候,又向tagViewList中添加了角色管理的标签)。
究竟是什么原因引起的路由跳转了两次呢?

路由多次跳转原因

后来经过万能的百度发现,使用RouterLink组件内嵌元素身上的绑定的事件会触发RouterLink组件的默认行为(触发路由跳转),这就解释了为什么路由发生了两次跳转。
第一次是通过标签的点击事件触发调用router.push()进行跳转的,第二次是因为触发了RouterLink自身的默认行为(跳转的路由正好是RouterLink组件to属性对应的路由,这里点击的是角色管理,路由从原本手动跳转到的用户管理,又二次跳转到角色管理)。

处理方法

弄明白为啥路由跳转两次后,处理这个问题就简单多了。究其根本都是因为触发了RouterLink组件本身的默认行为,所以只要阻止默认行为就可以了。这时候聪明的小伙伴已经想到了vue提供的prevent修饰符,只要内嵌元素的绑定事件上使用prevent修饰符,就可以阻止RouterLink组件默认行为的触发啦~~

最后

很少写输出文章,写作文笔有不好之处或知识点有误的地方还请各位看官多多包涵,如果有什么建议和想法也可以在评论区留言!最后创作不易,如果有所帮助请记得点赞呦~~ 🖊 ♥

参考博客::vue 内嵌@click修饰符用stop还是prevent