vue-element-admin顶部导航栏的修改

基于vue-element-admin的顶部一级导航栏的调整,因为一级路由过多导致其他元素被挤到第二行,故现在将原来一级路由数组拆分成两个数组,第二个数组以子菜单显示

关键处调整代码

html

html 复制代码
<el-menu
      :active-text-color="variables.menuActiveText"
      :default-active="activeMenu"
      mode="horizontal"
      @select="handleSelect"
    >
      <div v-for="item in displayedRoutes" :key="item.path" class="nav-item">
        <app-link :to="resolvePath(item)">
          <el-menu-item v-if="!item.hidden" :index="item.path">
            <i
              :class="
                item.meta && item.meta.icon ? item.meta.icon : 'el-icon-house'
              "
            ></i>
            {{
              item.meta ? item.meta.title : item.children[0].meta.title
            }}</el-menu-item
          >
        </app-link>
      </div>
      <el-submenu v-if="hiddenRoutes.length > 0" index="coll">
        <template slot="title"><i class="el-icon-more"></i></template>
        <div v-for="item in hiddenRoutes" :key="item.path" class="nav-item">
          <app-link :to="resolvePath(item)">
            <el-menu-item v-if="!item.hidden" :index="item.path">
              <i
                :class="
                  item.meta && item.meta.icon ? item.meta.icon : 'el-icon-house'
                "
              ></i>
              {{
                item.meta ? item.meta.title : item.children[0].meta.title
              }}</el-menu-item
            >
          </app-link>
        </div>
      </el-submenu>
    </el-menu>

js

javascript 复制代码
export default {
  name: "Topbar",
  components: {
    AppLink,
  },
  data() {
    return {
      activeIndex: "1",
      logo: titlePng,
      // avatar: sessionStorage.getItem("avatar"),
      routes: constantRoutes,
    };
  },
  computed: {
    ...mapGetters(["permission_routes", "async_routes", "avatar"]),
    activeMenu() {
      const route = this.$route;
      const { meta, path } = route;
      // if set path, the sidebar will highlight the path you set
      if (meta.activeMenu) {
        return meta.activeMenu;
      }
      // 如果是首页,首页高亮
      if (path === "/dashboard") {
        return "/";
      }
      // 如果不是首页,高亮一级菜单
      const activeMenu = "/" + path.split("/")[1];
      return activeMenu;
    },
    variables() {
      return variables;
    },
    sidebar() {
      return this.$store.state.app.sidebar;
    },
    displayedRoutes() {
      // 这里可以根据需要定义展示的路由项
      return this.routes.slice(0, 9); // 例如,展示前 9 个路由
    },
    hiddenRoutes() {
      // 返回剩余的路由项
      const hidden = this.routes.slice(9); // 省略的路由项
      return hidden.length > 0 ? hidden : []; // 只有在有省略项时返回
    },
  },
  watch: {
    activeMenu(newVal, oldVal) {
      this.handleSelect(newVal);
    },
  },
  mounted() {
    this.initCurrentRoutes();
  },
  methods: {
    // 通过当前路径找到二级菜单对应项,存到store,用来渲染左侧菜单
    initCurrentRoutes() {
      this.$router.addRoutes(this.async_routes);
      this.routes = this.permission_routes; // 动态路由赋值
      const { path } = this.$route;
      let route = this.routes.find(
        (item) => item.path === "/" + path.split("/")[1]
      );
      // 如果找不到这个路由,说明是首页
      if (!route) {
        route = this.routes.find((item) => item.path === "/");
      }
      this.$store.commit("permission/SET_CURRENT_ROUTES", route);
      this.setSidebarHide(route);
    },
    // 判断该路由是否只有一个子项或者没有子项,如果是,则在一级菜单添加跳转路由
    isOnlyOneChild(item) {
      if (item.children && item.children.length === 1) {
        return true;
      }
      return false;
    },
    resolvePath(item) {
      // 如果是个完成的url直接返回
      if (isExternal(item.path)) {
        return item.path;
      }
      // 如果是首页,就返回重定向路由
      if (item.path === "/") {
        const path = item.redirect;
        return path;
      }

      // 如果有子项,默认跳转第一个子项路由
      let path = "";
      /**
       * item 路由子项
       * parent 路由父项
       */
      const getDefaultPath = (item, parent) => {
        // 如果path是个外部链接(不建议),直接返回链接,存在个问题:如果是外部链接点击跳转后当前页内容还是上一个路由内容
        if (isExternal(item.path)) {
          path = item.path;
          return;
        }
        // 第一次需要父项路由拼接,所以只是第一个传parent
        if (parent) {
          path += parent.path + "/" + item.path;
        } else {
          path += "/" + item.path;
        }
        // 如果还有子项,继续递归
        if (item.children) {
          getDefaultPath(item.children[0]);
        }
      };

      if (item.children) {
        getDefaultPath(item.children[0], item);
        return path;
      }

      return item.path;
    },
    handleSelect(key, keyPath) {
      // 把选中路由的子路由保存store
      const route = this.routes.find((item) => item.path === key);
      this.$store.commit("permission/SET_CURRENT_ROUTES", route);
      this.setSidebarHide(route);
    },
    // 设置侧边栏的显示和隐藏
    setSidebarHide(route) {
      if (!route.children || route.children.length === 1) {
        this.$store.dispatch("app/toggleSideBarHide", true);
      } else {
        this.$store.dispatch("app/toggleSideBarHide", false);
      }
    },
    async logout() {
      await this.$store.dispatch("user/logout");
      this.$router.push(`/login?redirect=${this.$route.fullPath}`);
    },
    toggleFullScreen() {
      // 检查浏览器是否支持全屏 API
      if (screenfull.isEnabled) {
        screenfull.toggle(); // 切换全屏模式
      } else {
        console.warn("该浏览器不支持全屏");
      }
    },
  },
};
</script>

拆分逻辑是如果数组长度超过九个就拆分。如果想要根据不同浏览器窗口大小去拆分显示,需要去监听浏览器的实时宽度,计算整行所有元素的长度总和,如果超出则将超出的路由加入子菜单中显示

相关推荐
却尘14 分钟前
Next.js 请求最佳实践 - vercel 2026一月发布指南
前端·react.js·next.js
ccnocare15 分钟前
浅浅看一下设计模式
前端
Lee川18 分钟前
🎬 从标签到屏幕:揭秘现代网页构建与适配之道
前端·面试
Ticnix1 小时前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人1 小时前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl1 小时前
OpenClaw 深度技术解析
前端
崔庆才丨静觅1 小时前
比官方便宜一半以上!Grok API 申请及使用
前端
星光不问赶路人1 小时前
vue3使用jsx语法详解
前端·vue.js
天蓝色的鱼鱼1 小时前
shadcn/ui,给你一个真正可控的UI组件库
前端
布列瑟农的星空1 小时前
前端都能看懂的Rust入门教程(三)——控制流语句
前端·后端·rust