vue 如何做一个动态的 BreadCrumb 组件,el-breadcrumb ElementUI

news2024/9/21 0:27:27

vue 如何做一个动态的 BreadCrumb 组件 el-breadcrumb ElementUI

在这里插入图片描述

一、ElementUI 中的 BreadCrumb 定义

elementUI 中的 Breadcrumb 组件是这样定义的

<template>
  <el-breadcrumb separator="/">
    <el-breadcrumb-item :to="{ path: '/' }">主页</el-breadcrumb-item>
    <el-breadcrumb-item>系统配置</el-breadcrumb-item>
    <el-breadcrumb-item>基础配置</el-breadcrumb-item>
    <el-breadcrumb-item>自动登录</el-breadcrumb-item>
  </el-breadcrumb>
</template>

效果如图:
在这里插入图片描述

二、实现原理

我们需要实现的是,让它自己通过路由去填写这部分内容
原理是根据当前路由值,拆分成多个段,然后通过路由 path 去匹配对应的路由名称,再填入到上面的内容中即可。

比如:

1. 当前的路由值是 /system/normal-setup/auto-login

2. 通过拆分 / 生成一个数组

在这里插入图片描述

3. 依次匹配对应的路由名称

得到这个数组之后,依次去路由列表中匹配对应的路由名称

  • /system 系统配置
  • /system/normal-setup 基础配置
  • /system/normal-setup/auto-login 自动登录

4. 结果

这样就得到了一个 breadCrumb 数组,直接遍历这个数组,显示 BreadCrumb 即可

三、具体实现过程

知道了上面的实现原理,才会有具体的实现过程,这个过程还是有点麻烦的。

1. 处理路由数据

项目中用到的路由数据是这样的树形结构,路由数据的定义是这样的,里面的 children 可以嵌套任意层:

interface MenuEntity {
    id?: number | null,
    parent_id: number,
    name: string,
    icon?: string,
    type: EnumMenuType, // 1->目录 2->菜单 3->按钮 4->外链
    path: string,
    component?: string,
    visible: EnumMenuVisible, // 1->可见 2->隐藏 默认为1
    redirect: string,
    sort: number, // 默认为 20
    perm: string, // permission
    created_at?: string,
    updated_at?: string,
    children?: MenuEntity[]
}

实际的数据是这样的:

{
    "name": "系统配置",
    "id": 10,
    "parent_id": -1,
    "type": 1,
    "path": "/system",
    "component": "",
    "visible": 1,
    "redirect": "",
    "perm": "",
    "sort": 100,
    "icon": "Setting",
    "created_at": "2024-02-26T14:55:12+08:00",
    "updated_at": "2024-02-26T16:12:34+08:00",
    "children": [
        {
            "name": "基础配置",
            "id": 12,
            "parent_id": -1,
            "type": 1,
            "path": "/system/normal-setup",
            "component": "",
            "visible": 1,
            "redirect": "",
            "perm": "",
            "sort": 10,
            "icon": "CreditCard",
            "created_at": "2024-02-26T15:20:15+08:00",
            "updated_at": "2024-02-26T16:11:56+08:00",
            "children": [
                {
                    "name": "自动登录",
                    "id": 13,
                    "parent_id": 12,
                    "type": 2,
                    "path": "/system/normal-setup/auto-login",
                    "component": "System/NormalSetup/AutoLoginSetup.vue",
                    "visible": 1,
                    "redirect": "",
                    "perm": "",
                    "sort": 30,
                    "icon": "User",
                    "created_at": "2024-02-26T15:24:18+08:00",
                    "updated_at": "2024-05-17T14:11:52+08:00",
                    "children": []
                },
                {
                    "name": "系统更新",
                    "id": 28,
                    "parent_id": 12,
                    "type": 2,
                    "path": "/system/normal-setup/system-update",
                    "component": "System/SystemUpdate.vue",
                    "visible": 1,
                    "redirect": "",
                    "perm": "",
                    "sort": 50,
                    "icon": "UploadFilled",
                    "created_at": "2024-02-26T16:19:49+08:00",
                    "updated_at": "2024-05-17T14:11:39+08:00",
                    "children": []
                },
                {
                    "name": "申请厂家技术支持",
                    "id": 29,
                    "parent_id": 12,
                    "type": 2,
                    "path": "/system/normal-setup/factory-help",
                    "component": "User/Space.vue",
                    "visible": 1,
                    "redirect": "",
                    "perm": "",
                    "sort": 40,
                    "icon": "SuitcaseLine",
                    "created_at": "2024-02-26T16:20:11+08:00",
                    "updated_at": "2024-03-27T09:04:20+08:00",
                    "children": []
                }
            ]
        }
    ]
}
        

为了好后续匹配 path 到路由名,需要将这个数据平化成一个数组,并构建一个 Map<path, RouteItem> 这样的一个 Map 数据,目的是当执行下面操作时,取到对应的路由数据

flatMenuPathNameMap.get('/system')

// 最终取到这样的数据
{
    "name": "系统配置",
    "id": 10,
    "parent_id": -1,
    "type": 1,
    "path": "/system",
    "component": "",
    "visible": 1,
    "redirect": "",
    "perm": "",
    "sort": 100,
    "icon": "Setting",
    "created_at": "2024-02-26T14:55:12+08:00",
    "updated_at": "2024-02-26T16:12:34+08:00",
}

平化树形数据、生成对应的 Map 数据结构:

/**
 * 菜单相关
 * 这里是单独放到了 pinia 中
 */
export const useMenuStore = defineStore('menuStore', {
    state: () => ({
        menus: [] as Array<RouteRecordRaw>,
        flatMenuArray: [] as Array<MenuEntity>,
        flatMenuPathNameMap: new Map<string, string>()
    }),
    actions: {
        generateMenuArrayAndMap(){
            let menuString = localStorage.getItem('dataMenu')
            let menusCache = menuString ? JSON.parse(menuString) as Array<MenuEntity> : [] as Array<MenuEntity>
            let flatMenuArray = recursionMenuData(menusCache)
            this.flatMenuArray = flatMenuArray
            this.flatMenuPathNameMap = new Map(flatMenuArray.map(item => [item.path, item.name]))

            // 递归方法,平化菜单数据
            function recursionMenuData(menuArray: Array<MenuEntity>){
                let tempArray: Array<MenuEntity> = []
                menuArray.forEach(item => {
                    if (item.children && item.children.length > 0){
                        tempArray = tempArray.concat(recursionMenuData(item.children))
                        // 添加本身,并去除 children 属性
                        delete item.children
                        tempArray.push(item)
                    } else {
                        tempArray.push(item)
                    }
                })
                return tempArray
            }
        },
     }
})

使用的时候

import {useMenuStore, useProjectStore} from "./pinia";
const storeMenu = useMenuStore()
// 当执行下面的操作时就会补全  storeMenu.flatMenuArray 和  storeMenu.flatMenuPathNameMap
storeMenu.generateMenuArrayAndMap()

路由树的基础数据是这样的:

在这里插入图片描述

平化后的路由数组是这样的:
在这里插入图片描述

最终生成的 Map 数据是这样的:

在这里插入图片描述

2. 拆分当前路由 path,并匹配

比如当前路由是 /system/normal-setup/auto-login,把它通过 / 拆分之后就是这样的结果

import {useRoute} from "vue-router";
const route = useRoute()
let routeSectionArray = route.path.split('/').filter(item => item !== '')
// 这样拆分之后,前面会多出一个空白的 "" ,所以这里剔除了它

在这里插入图片描述
接下来要做的就是通过上面的 routerSectionArray 生成下面的几个路由组合,再去之前生成的 Map 中匹配对应的路由名即可

  • /system
  • /system/normal-setup
  • /system/normal-setup/auto-login

匹配之后就是这样的结果

  • /system 系统配置
  • /system/normal-setup 基础配置
  • /system/normal-setup/auto-login 自动登录

代码是这样的:

import {useRoute} from "vue-router";
import {onMounted, ref} from "vue";
import {useMenuStore} from "@/pinia";

const storeMenu = useMenuStore()
const route = useRoute()

const breadCrumbArray = ref<Array<{name: string, path: string}>>([])

onMounted(()=>{
    let routeSectionArray = route.path.split('/').filter(item => item !== '')
    console.log(routeSectionArray)
    routeSectionArray.forEach((_, index) => {
        let path = `/${routeSectionArray.slice(0,index + 1).join('/')}`
        let pathName = storeMenu.flatMenuPathNameMap.get(path)
        console.log('---',pathName, path)
        if (pathName){
            breadCrumbArray.value.push({name: pathName, path: path})
        }
    })
})

四、搭配其它组件构建页面

弄好上面的 BreadCrumb 组件之后,就可以不用再管它内部的内容了,它会自动根据当前路由值生成对应的内容。
这样我们就可以放心的把它放到页面结构中了。

比如我的页面主要结构是这样的:

在这里插入图片描述

Toolerbar.vue

<template>
    <div class="tool-bar">
        <div class="left">
            <Breadcrumb/>
            <slot name="left"/>
        </div>
        <div class="center">
            <slot name="center"/>
        </div>
        <div class="right">
            <slot name="right"/>
        </div>
    </div>
</template>

<script setup lang="ts">

import Breadcrumb from "@/layout/Breadcrumb.vue";
</script>


<style scoped lang="scss">
.tool-bar{
    padding: 0 20px;
    align-items: center;
    min-height: 50px;
    display: flex;
    flex-flow: row wrap;
    justify-content: space-between;
    .left{
        display: flex;
        flex-flow: row nowrap;
        justify-content: flex-start;
        align-items: center;
        flex-shrink: 0;
    }
    .center{
        display: flex;
        flex-flow: row nowrap;
        justify-content: flex-start;
        align-items: center;
        flex-grow: 1;
        flex-shrink: 0;
    }
    .right{
        display: flex;
        flex-flow: row nowrap;
        justify-content: flex-start;
        align-items: center;
        flex-shrink: 0;
    }
}
</style>

Breadcrumb.vue

<template>
    <el-breadcrumb separator="/">
        <el-breadcrumb-item :to="{ path: '/' }">主页</el-breadcrumb-item>
        <el-breadcrumb-item
            v-for="item in breadCrumbArray"
            :key="item">{{ item.name }}</el-breadcrumb-item>
    </el-breadcrumb>
</template>

<script setup lang="ts">
import {useRoute} from "vue-router";
import {onMounted, ref} from "vue";
import {useMenuStore} from "@/pinia";

const storeMenu = useMenuStore()
const route = useRoute()

defineProps( {
    height: { // 高度
        type: Number,
        default: 100
    }
})

const breadCrumbArray = ref<Array<{name: string, path: string}>>([])

onMounted(()=>{
    let routeSectionArray = route.path.split('/').filter(item => item !== '')
    routeSectionArray.forEach((_, index) => {
        let path = `/${routeSectionArray.slice(0,index + 1).join('/')}`
        let pathName = storeMenu.flatMenuPathNameMap.get(path)
        console.log('---',pathName, path)
        if (pathName){
            breadCrumbArray.value.push({name: pathName, path: path})
        }
    })
})



</script>

<style lang="scss" scoped>
@import "../assets/scss/plugin";


</style>

实际页面中使用时这样:

<template>
    <Container>
    
        <Toolbar>
            <template #left>
            </template>
            <template #center>
            </template>
            <template #right>
            </template>
        </Toolbar>
        
        <Content>
        </Content>
    </Container>
<template>

五、结果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1933407.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法 —— LRU算法

算法 —— LRU算法 LRULRU算法的工作原理&#xff1a;实现方法&#xff1a;性能考虑&#xff1a; 模拟过程splice函数对于std::list和std::forward_list基本语法&#xff1a;功能描述&#xff1a; 示例&#xff1a;注意事项&#xff1a; 如果大家已经学习过了Cache的替换算法和…

《人性的弱点》

This book is called ‘How to Win Friends & Influence People’. [COPY] 卡耐基《人性的弱点》有什么干货么&#xff1f;

自学鸿蒙HarmonyOS的ArkTS语言<十>@BuilderParam装饰器

作用&#xff1a;当子组件多处使用时&#xff0c;给某处的子组件添加特定功能 一、初始化 1、只能被Builder装饰的方法初始化 2、使用所属自定义组件的builder方法初始化 3、使用父组件的builder方法初始化 - 把父组件的builder传过去&#xff0c;参数名和子组件的builderPar…

【信号频率估计】MVDR算法及MATLAB仿真

目录 一、MVDR算法1.1 简介1.2 原理1.3 特点1.3.1 优点1.3.2 缺点 二、算法应用实例2.1 信号的频率估计2.2 MATLAB仿真代码 三、参考文献 一、MVDR算法 1.1 简介 最小方差无失真响应&#xff08;Mininum Variance Distortionless Response&#xff0c;MVDR&#xff09;算法最…

AI初学者的利器——香橙派AIpro

目录 引言香橙派介绍公司简介&#xff08;来自官网&#xff09;香橙派AIpro介绍香橙派AIPro硬件规格参数开发板接口详情系统登陆与使用指示灯 AI运行实例AI CPU和control CPU的设置方法香橙派AIpro cpu知识查询AIcpu占用率与cpu类别设置 Juypter lab使用JuypterLab介绍JuypterL…

8款可以替代Axure的设计软件推荐

一个好的原型设计工具对于产品经理或者UI/UX设计师来说非常重要。一个好的原型设计软件可以帮助你快速构建一个还原度高、信息结构清晰的原型图&#xff0c;也可以大大降低工作中与同事的沟通成本&#xff0c;更高效地推进工作。 那么&#xff0c;什么是易于使用和免费的原型设…

C51语言及通用I/O口应用

4.1 C51的程序结构 4.2 C51的数据结构 4.3 C51与汇编的混合编程 4.4 C51仿真开发方法 4.5 通用I/O口的简单应用 4.6 通用I/O口的进阶应用 4.1.1 C51语言概述 C51语言是51单片机的一种高级编程语言&#xff0c;与低级语言的汇编语言相比&#xff0c;一方面具有结构化语…

Chapter12 屏幕后处理效果——Shader入门精要学习笔记

Chapter12 屏幕后处理效果 一、屏幕后处理概述以及基本脚本系统1.OnRenderImage 函数 —— 获取屏幕图像2.Graphics.Blit 函数 —— 使用特定的Shader处理3.在Unity中实现屏幕后处理的基本流程4.屏幕后处理基类 二、调整亮度、饱和度和对比度1.BrightnessSaturationAndContrast…

Postman安装使用教程(详解)

目录 一、Postman是什么 二、安装系统要求 三、下载Postman 四、注册和登录Postman 五、创建工作空间 六、创建请求 一、Postman是什么 在安装之前&#xff0c;让我们先来简单了解一下Postman。Postman是一个流行的API开发工具&#xff0c;它提供了友好的用户界面用于发送…

简单实用的企业舆情安全解决方案

前言&#xff1a;企业舆情安全重要吗&#xff1f;其实很重要&#xff0c;尤其面对负面新闻&#xff0c;主动处理和应对&#xff0c;可以掌握主动权&#xff0c;避免股价下跌等&#xff0c;那么如何做使用简单实用的企业舆情解决方案呢&#xff1f; 背景 好了&#xff0c;提取词…

python CMD命令行传参实现:argparse、click、fire

1、argparse 设置传入和默认参数&#xff0c;也可以通过–help参考具体设置参数 bool值 参考&#xff1a; https://docs.python.org/zh-cn/3/howto/argparse.html https://www.bilibili.com/video/BV1nb41157Zc expected one argumrnt 报错&#xff0c;传入坐标类型字符串…

MYSQL 四、mysql进阶 9(数据库的设计规范)

一、为什么需要数据库设计 二、范 式 2.1 范式简介 在关系型数据库中&#xff0c;关于数据表设计的基本原则、规则就称为范式。 可以理解为&#xff0c;一张数据表的设计结 构需要满足的某种设计标准的 级别 。要想设计一个结构合理的关系型数据库&#xff0c;必须满足一定的…

couldn‘t read native报错!Typora中使用Pandoc导出Word失败的解决方法

couldn‘t read native报错&#xff01;Typora中使用Pandoc导出Word失败的解决方法 一、问题描述 在Typora中使用Pandoc将markdown文件导出为word文件时&#xff0c;发生如下图所示错误: 在网上找了资料以后&#xff0c;发现是因为md文件里面有表格&#xff0c;如果把表格删掉…

【深度学习】PyTorch框架(4):初始网络、残差网络 和密集连接网络

1、引言 在本篇文章中&#xff0c;我们将深入探讨并实现一些现代卷积神经网络&#xff08;CNN&#xff09;架构的变体。近年来&#xff0c;学界提出了众多新颖的网络架构。其中一些最具影响力&#xff0c;并且至今仍然具有重要地位的架构包括&#xff1a;GoogleNet/Inception架…

linux搭建mysql主从复制(一主一从)

目录 0、环境部署 1、主服务器配置 1.1 修改mysql配置文件 1.2 重启mysql 1.3 为从服务器授权 1.4 查看二进制日志坐标 2、从服务器配置 2.1 修改mysql配置文件 2.2 重启mysql 2.3 配置主从同步 2.4 开启主从复制 3、验证主从复制 3.1 主服务器上创建test…

Stable Diffusion【美女写实模型】:亚洲女性写实大模型,皮肤细腻光滑!

今天介绍一款专注于亚洲女性写实的SDXL模型&#xff1a;XXMix_9realisticSDXL。该模型绘图质量相当出色&#xff1a;面部在真实感基础上增加了一些轻度的美颜效果&#xff1b;以及增强的光影特效方面效果&#xff1b;只需要简单提示语就可以画出典型的亚洲女孩风格高质量图像。…

通过vue3 + TypeScript + uniapp + uni-ui 实现下拉刷新和加载更多的功能

效果图: 核心代码: <script lang="ts" setup>import { ref, reactive } from vue;import api from @/request/api.jsimport empty from @/component/empty.vueimport { onLoad,onShow, onPullDownRefresh, onReachBottom } from @dcloudio/uni-applet form …

Gradio技术入门(一)

Gradio是一个开源的Python库&#xff0c;旨在让创建机器学习模型的应用界面变得简单快捷。 官网&#xff1a;格罗特 (gradio.app) 一、基本概述 1&#xff0c;技术概述 1. 定义与用途 Gradio通过Python生成一套HTML页面&#xff0c;其中编写好了大部分的组件&#xff0c;主…

《大数据基础》相关知识点及考点,例题

1.6大数据计算模式 1、MapReduce可以并行执行大规模数据处理任务&#xff0c;用于大规模数据集&#xff08;大于1TB&#xff09;的并行运算。MapReduce 极大地方便了分布式编程工作&#xff0c;它将复杂的、运行于大规模集群上的并行计算过程高度地抽象为两个函数一一Map和Redu…

数据库系统概论:数据库完整性

引言 数据库是现代信息系统的心脏&#xff0c;数据的准确性和一致性对于业务流程至关重要。数据库完整性是确保数据质量的基石&#xff0c;它涵盖了数据的正确性、相容性和一致性&#xff0c;是数据安全与业务连续性的保障。 数据库完整性是指数据的精确性、可靠性和逻辑一致…