ruoyi vue3 自定义子路由面包屑处理

效果图:

a/b/c/新增、编辑、详情之类的 需要展示在面包屑中 因为不需要首页就把首页删除了

代码:
html
html 复制代码
<template>
  <div class="breadcrumb-box">
    当前位置:
    <el-breadcrumb class="app-breadcrumb" separator="/">
      <!-- <transition-group name="breadcrumb"> -->
      <el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
        <span
          :style="{
            color: index == levelList.length - 1 ? '#ffffff' : '#b0c6d6',
          }"
          >{{ item.meta.title }}</span
        >
      </el-breadcrumb-item>
      <!-- </transition-group> -->
    </el-breadcrumb>
  </div>
</template>
js
javascript 复制代码
<script setup>
import usePermissionStore from "@/store/modules/permission";
import useRouteToPageStore from "@/store/modules/routeToPage";
const route = useRoute();
const permissionStore = usePermissionStore();
const routeToPageStore = useRouteToPageStore();

const levelList = ref([]);
// 在路由树中查找匹配的路由
function findRouteByPath(path, routes) {
  for (const route of routes) {
    if (route.path === path) {
      return route;
    }
    if (route.children) {
      const found = findRouteByPath(path, route.children);
      if (found) return found;
    }
  }
  return null;
}
// 获取完整的面包屑路径
function getBreadcrumb() {
  let matched = [];
  // 1. 获取当前路由的breadcrumbMenu(如果有)
  const breadcrumbMenu = route.meta?.breadcrumbMenu;
  const rootMenu = route.meta?.rootMenu;
  // 2. 如果有breadcrumbMenu,则从breadcrumbMenu开始构建面包屑
  if (breadcrumbMenu) {
    // 在权限路由中查找breadcrumbMenu对应的路由
    const activeRoute = findRouteByPath(breadcrumbMenu, permissionStore.routes);
    if (activeRoute) {
      // 获取activeRoute的完整路径链
      const activeMatched = getRouteChain(
        activeRoute,
        permissionStore.routes,
        [],
        rootMenu
      );
      matched = activeMatched.filter((item) => item.meta?.title && item.meta);
    }
    // 添加当前路由(编辑/新增页面)
    if (route.meta?.title) {
      matched.push({
        path: route.path,
        meta: { title: routeToPageStore.pageTitle || route.meta.title },
        redirect: "noRedirect",
      });
    }
  } else {
    // 3. 没有breadcrumbMenu,使用常规方法
    const pathNum = findPathNum(route.path);
    if (pathNum > 2) {
      const reg = /\/\w+/gi;
      const pathList = route.path.match(reg).map((item, index) => {
        if (index !== 0) item = item.slice(1);
        return item;
      });
      getMatched(pathList, permissionStore.defaultRoutes, matched);
    } else {
      matched = route.matched.filter((item) => item.meta && item.meta.title);
    }
    levelList.value = matched.filter((item) => item.meta && item.meta.title);
  }

  levelList.value = matched;
}
function findPathNum(str, char = "/") {
  let index = str.indexOf(char);
  let num = 0;
  while (index !== -1) {
    num++;
    index = str.indexOf(char, index + 1);
  }
  return num;
}
function getMatched(pathList, routeList, matched) {
  let data = routeList.find(
    (item) =>
      item.path == pathList[0] || (item.name += "").toLowerCase() == pathList[0]
  );
  if (data) {
    matched.push(data);
    if (data.children && pathList.length) {
      pathList.shift();
      getMatched(pathList, data.children, matched);
    }
  }
}
// 获取路由的完整链(从根到当前路由)
function getRouteChain(route, routes, chain = [], rootMenu) {
  if (!route) return chain;
  // 添加到链中
  chain.unshift(route);
  if (route.path !== rootMenu) {
    const parentPath = route.path.split("/").slice(0, -1).join("/") || rootMenu;
    const parentRoute = findRouteByPath(parentPath, routes);
    if (parentRoute) {
      return getRouteChain(parentRoute, routes, chain);
    }
  }

  return chain;
}

watchEffect(() => {
  if (route.path.startsWith("/redirect/")) {
    return;
  }
  getBreadcrumb();
});
getBreadcrumb();
</script>
css
css 复制代码
<style lang="scss" scoped>
.breadcrumb-box {
  height: 40px;
  padding-left: 16px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  font-family: Source Han Sans CN, Source Han Sans CN;
  font-weight: 400;
  font-size: 12px;
  color: #ffffff;
  border-bottom: 1px solid #1c3667;
  background-color: #0a0a0a;
  .breadcrumb-container {
    font-family: Source Han Sans CN, Source Han Sans CN;
    font-weight: 400;
    font-size: 12px;
    height: 22px;
  }
}
.app-breadcrumb {
  display: flex;
  align-items: center;
  height: 22px;
}
.app-breadcrumb.el-breadcrumb {
  display: flex;
  align-items: center;
  font-size: 12px;
  .no-redirect {
    color: #97a8be;
    cursor: text;
  }
}
:deep(.el-breadcrumb__separator) {
  color: #888d98;
}
</style>
router/index.js文件

// 动态路由,基于用户权限动态去加载 在ruoyi原有的这个中加入新的 比如新增页面

export const dynamicRoutes =

javascript 复制代码
{
    path: "/system/user/data",
    component: Layout,
    hidden: true,
    permissions: ["system:user:list"],
    children: [
      {
        path: "",
        component: () => import("@/views/system/user/components/edit"),
        name: "UserEdit",
        meta: {
          title: "用户管理",
          activeMenu: "/system/user", //当前高亮的路由
          rootMenu: "/system", // 查找的根路由
          breadcrumbMenu: "user", // 面包屑菜单
        },
      },
    ],
  },
处理动态title 使用 pinia

title: "用户管理",
persist: true, 数据持久化 可以使用pinia的插件 pinia-plugin-persistedstate
npm i pinia-plugin-persistedstate

yarn add pinia-plugin-persistedstate

ruoyi自带 store/index.js 引入持久化插件

const store = createPinia();

import piniaPluginPersistedstate from "pinia-plugin-persistedstate";

store.use(piniaPluginPersistedstate); // 注入插件

export default store;

因为还有其他逻辑之后我新建一个文件 store/modules/routeToPage.js
javascript 复制代码
const useRouteToPageStore = defineStore("routeToPage", {
  state: () => ({
    editParams: null, // 存储编辑页参数
    pageTitle: null, // 存储页面标题
  }),
  actions: {
    setEditParams(params) {
      this.editParams = params;
    },
    clearEditParams() {
      this.editParams = null;
    },
    setPageTitle(title) {
      this.pageTitle = title;
    },
    clearPageTitle() {
      this.pageTitle = null;
    },
  },
  persist: true,
});

export default useRouteToPageStore;

大功告成!!!

相关推荐
学传打活1 天前
【边打字.边学昆仑正义文化】_进阶篇5 宇宙星系的运转(续1)
微信公众平台·1024程序员节·汉字·昆仑正义文化
fangzhanpeng1689 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心11 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u01030552717 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u01030552717 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝19 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u01030552719 天前
Java图像处理实战指南
人工智能·1024程序员节
u01030552719 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u01030552722 天前
Java实用类应用精讲
人工智能·1024程序员节
u01030552722 天前
Java I/O核心操作实战
人工智能·1024程序员节