Vue + Element Plus 实现权限管理系统(六):实现导航栏标签页

在后台管理系统页面中一般都会有导航栏标签这一功能,它可以让我们点击过的菜单以 tab 标签栏的形式展现出来,同时右键标签可以展示刷新页面,关闭当前,关闭其它,全部关闭选项,如下图所示

本篇文章将介绍导航栏标签的具体实现

新增标签

elementplus 为我们提供了 Tag 组件,我们可以直接使用

首先在全局状态管理器store/index.ts中定义一个 state:navTags 用于存放点击过的标签数据,这些数据包含的字段包括菜单名name以及跳转路由path,同时里面默认添加一个首页的标签。还需要定义一个添加标签的函数放到 actions 中

当点击菜单的时候需要在 navTags 新增一条标签数据,因此可以在路由守卫中调用 addTags 函数

js 复制代码
//router/index.ts
router.beforeEach(async (to, from, next) => {
  //.....
  if (homeStore.menuList.length) {
   //....
    homeStore.addTags({ name: to.name as string, path: to.path });

    next();
    return;
  }
 ....

  next({ ...to, replace: true });
});

export default router;

然后在 navbar 中使用 tag 组件,同时添加一些样式

这里有一个属性 effect,可以设置标签主题,当当前标签的 path 和当前页面路由 path 一样的话就给它设置为dark主题。获取当前页面的 path 其实很简单,在navbar.vue中监听路由变化即可

此时点击菜单的时候我们已经可以将标签一个个添加上去了,此时我们还需要让标签被点击然后跳转到对应页面

js 复制代码
const handelTo = (item: any) => {
  router.push(item.path);
};

删除标签

Tag 组件可以设置 closable 定义一个标签是否可移除,同时提供一个点击 x 的 close 事件,我们可以在这个事件中删除当前标签在navTags中的数据,这里我们还需要判断删除的是不是当前页面,如果是的话则还需要跳转到最后一个标签选项

js 复制代码
<el-tag
  v-for="(item, index) in homeStore.navTags"
  @click="handelTo(item)"
  :key="item.name"
  class="ml-2 cursor-pointer flex-shrink-0"
  :effect="currentPath === item.path ? 'dark' : ''"
  type="primary"
  :closable="item.path != '/'"
  @close="handleClose(index, item.path)"
>
          {{ item.name }}
        </el-tag>
js 复制代码
const handleClose = (index: number, path: string) => {
  homeStore.navTags.splice(index, 1);
  //判断是否为当前页面,如果是则跳转至最后一个标签页
  if (path === currentPath.value) {
    const length = homeStore.navTags.length;
    length && router.push(homeStore.navTags[length - 1].path);
  }
};

到这里导航标签功能基本完成,接下来来实现点击鼠标右键出现刷新页面,关闭当前等选项功能

右键列表功能

在 src/component 中新增一个 tagsview 组件用于实现右键列表功能

js 复制代码
<template>
  <div class="bg-white shadow-lg rounded-md text-[14px] overflow-hidden cursor-pointer">
    <div class="p-1 hover:bg-[#E0E0E0] flex items-center" @click="refresh">
      <el-icon>
        <Refresh />
      </el-icon><span>刷新页面</span>
    </div>
    <div class="p-1 hover:bg-[#E0E0E0] flex items-center" @click="emits('closeCur')">
      <el-icon>
        <CloseBold />
      </el-icon><span>关闭当前</span>
    </div>
    <div class="p-1 hover:bg-[#E0E0E0] flex items-center" @click="closeOtherTags">
      <el-icon>
        <Close />
      </el-icon><span>关闭其它</span>
    </div>
    <div class="p-1 hover:bg-[#E0E0E0] flex items-center" @click="closeAllTags">
      <el-icon>
        <Close />
      </el-icon><span>全部关闭</span>
    </div>
  </div>
</template>

<script lang="ts" setup>
import home from ".././../store";
import { useRouter } from "vue-router";
const router = useRouter();
const homeStore = home();
type Props = {
  tag: {
    path: string;
    name: string;
  };
};

const props = defineProps<Props>();
type Emits = {
  (e: "closeCur"): void;
  (e: "closeTagView"): void;
};
const emits = defineEmits<Emits>();
//刷新页面
const refresh = () => {
  window.location.reload();
};
//关闭其它
const closeOtherTags = () => {
  homeStore.$patch({
    navTags: [{ name: "首页", path: "/" }, props.tag],
  });
  router.push(props.tag.path);
  emits("closeTagView");
};
//关闭所有
const closeAllTags = () => {
  homeStore.$patch({
    navTags: [{ name: "首页", path: "/" }],
  });
  router.push("/");
  emits("closeTagView");
};
</script>

vue 中鼠标右击事件可以使用@contextmenu,同时我们需要知道当前点击的位置,然后根据当前位置定位,所以可以将事件参数$event传入,并且要将当前点击的标签参数传入

js 复制代码
<el-tag
  @contextmenu.prevent="openMenu($event, item.path)"
  v-for="(item, index) in homeStore.navTags"
  @click="handelTo(item)"
  :key="item.name"
  class="ml-2 cursor-pointer flex-shrink-0"
  :effect="currentPath === item.path ? 'dark' : ''"
  type="primary"
  :closable="item.path != '/'"
  @close="handleClose(index, item.path)"
>
          {{ item.name }}
          <teleport to="body">
            <tagsview v-if="isTagView && currentTagPath === item.path" @closeTagView="isTagView = false" :tag="item"
              class="w-[100px] fixed" :style="tagViewStyle" @closeCur="handleClose(index, item.path)" />
          </teleport>
        </el-tag>

这里我们可以通过$event中的clientXclientY获取到当前点击位置距离浏览器窗口的坐标,即固定定位(fixed),刚好可以将列表定位到这里。 同时添加一个document的点击事件用于关闭列表

js 复制代码
const listener = () => {
  isTagView.value = false;
  document.removeEventListener("click", listener);
};
const tagViewStyle = ref({});
const openMenu = (e: any, path: string) => {
  isTagView.value = true;
  document.addEventListener("click", listener);

  tagViewStyle.value = {
    left: e.clientX + "px",
    top: e.clientY + "px",
  };
};

到这里简单的右键列表功能就已经实现了

代码地址

相关推荐
余生H16 分钟前
前端的全栈混合之路Meteor篇:关于前后端分离及与各框架的对比
前端·javascript·node.js·全栈
花花鱼17 分钟前
@antv/x6 导出图片下载,或者导出图片为base64由后端去处理。
vue.js
程序员-珍19 分钟前
使用openapi生成前端请求文件报错 ‘Token “Integer“ does not exist.‘
java·前端·spring boot·后端·restful·个人开发
axihaihai24 分钟前
网站开发的发展(后端路由/前后端分离/前端路由)
前端
流烟默36 分钟前
Vue中watch监听属性的一些应用总结
前端·javascript·vue.js·watch
2401_857297911 小时前
招联金融2025校招内推
java·前端·算法·金融·求职招聘
茶卡盐佑星_1 小时前
meta标签作用/SEO优化
前端·javascript·html
Ink1 小时前
从底层看 path.resolve 实现
前端·node.js
金灰1 小时前
HTML5--裸体回顾
java·开发语言·前端·javascript·html·html5
茶卡盐佑星_1 小时前
说说你对es6中promise的理解?
前端·ecmascript·es6