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>

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

相关推荐
腾讯TNTWeb前端团队3 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰6 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪7 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪7 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy7 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom8 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom8 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom8 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom8 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom8 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试