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",
  };
};

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

代码地址

相关推荐
别拿曾经看以后~43 分钟前
【el-form】记一例好用的el-input输入框回车调接口和el-button按钮防重点击
javascript·vue.js·elementui
我要洋人死1 小时前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人1 小时前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人1 小时前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR1 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香1 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596931 小时前
前端预览word、excel、ppt
前端·word·excel
小华同学ai1 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_9151 小时前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍