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;

大功告成!!!

相关推荐
开开心心就好2 天前
内存清理工具开源免费,自动优化清理项
linux·运维·服务器·python·django·pdf·1024程序员节
张萌杰5 天前
深度学习的基础知识(常见名词解释)
人工智能·深度学习·机器学习·1024程序员节
开开心心就好6 天前
免费无广告卸载工具,轻便安全适配全用户
linux·运维·服务器·网络·安全·启发式算法·1024程序员节
开开心心就好6 天前
图片格式转换工具,右键菜单一键转换简化
linux·运维·服务器·python·django·pdf·1024程序员节
徐子童9 天前
网络协议---TCP协议
网络·网络协议·tcp/ip·面试题·1024程序员节
扫地的小何尚10 天前
NVIDIA RTX PC开源AI工具升级:加速LLM和扩散模型的性能革命
人工智能·python·算法·开源·nvidia·1024程序员节
数据皮皮侠AI11 天前
上市公司股票名称相似度(1990-2025)
大数据·人工智能·笔记·区块链·能源·1024程序员节
开开心心就好12 天前
系统清理工具清理缓存日志,启动卸载管理
linux·运维·服务器·神经网络·cnn·pdf·1024程序员节
Evan东少14 天前
[踩坑]笔记本Ubuntu20.04+NvidiaRTX5060驱动+cuda+Pytorch+ROS/Python实现人脸追踪(环境准备)
1024程序员节
不爱编程的小陈16 天前
C/C++每日面试题
面试·职场和发展·1024程序员节