vue動(dòng)態(tài)的 BreadCrumb 組件el-breadcrumb ElementUI詳解
,本文通過(guò)圖文示例代碼相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下
vue 如何做一個(gè)動(dòng)態(tài)的 BreadCrumb 組件 el-breadcrumb ElementUI

一、ElementUI 中的 BreadCrumb 定義
elementUI 中的 Breadcrumb 組件是這樣定義的
<template>
<el-breadcrumb separator="/">
<el-breadcrumb-item :to="{ path: '/' }">主頁(yè)</el-breadcrumb-item>
<el-breadcrumb-item>系統(tǒng)配置</el-breadcrumb-item>
<el-breadcrumb-item>基礎(chǔ)配置</el-breadcrumb-item>
<el-breadcrumb-item>自動(dòng)登錄</el-breadcrumb-item>
</el-breadcrumb>
</template>效果如圖:

二、實(shí)現(xiàn)原理
我們需要實(shí)現(xiàn)的是,讓它自己通過(guò)路由去填寫(xiě)這部分內(nèi)容
原理是根據(jù)當(dāng)前路由值,拆分成多個(gè)段,然后通過(guò)路由 path 去匹配對(duì)應(yīng)的路由名稱,再填入到上面的內(nèi)容中即可。
比如:
1. 當(dāng)前的路由值是 /system/normal-setup/auto-login 2. 通過(guò)拆分 / 生成一個(gè)數(shù)組

3. 依次匹配對(duì)應(yīng)的路由名稱
得到這個(gè)數(shù)組之后,依次去路由列表中匹配對(duì)應(yīng)的路由名稱
/system系統(tǒng)配置/system/normal-setup- 基礎(chǔ)配置
/system/normal-setup/auto-login自動(dòng)登錄
4. 結(jié)果
這樣就得到了一個(gè) breadCrumb 數(shù)組,直接遍歷這個(gè)數(shù)組,顯示 BreadCrumb 即可
三、具體實(shí)現(xiàn)過(guò)程
知道了上面的實(shí)現(xiàn)原理,才會(huì)有具體的實(shí)現(xiàn)過(guò)程,這個(gè)過(guò)程還是有點(diǎn)麻煩的。
1. 處理路由數(shù)據(jù)
項(xiàng)目中用到的路由數(shù)據(jù)是這樣的樹(shù)形結(jié)構(gòu),路由數(shù)據(jù)的定義是這樣的,里面的 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->可見(jiàn) 2->隱藏 默認(rèn)為1
redirect: string,
sort: number, // 默認(rèn)為 20
perm: string, // permission
created_at?: string,
updated_at?: string,
children?: MenuEntity[]
}實(shí)際的數(shù)據(jù)是這樣的:
{
"name": "系統(tǒng)配置",
"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": "基礎(chǔ)配置",
"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": "自動(dòng)登錄",
"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": "系統(tǒng)更新",
"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": "申請(qǐng)廠家技術(shù)支持",
"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": []
}
]
}
]
}為了好后續(xù)匹配 path 到路由名,需要將這個(gè)數(shù)據(jù)平化成一個(gè)數(shù)組,并構(gòu)建一個(gè) Map<path, RouteItem> 這樣的一個(gè) Map 數(shù)據(jù),目的是當(dāng)執(zhí)行下面操作時(shí),取到對(duì)應(yīng)的路由數(shù)據(jù)
flatMenuPathNameMap.get('/system')
// 最終取到這樣的數(shù)據(jù)
{
"name": "系統(tǒng)配置",
"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",
}平化樹(shù)形數(shù)據(jù)、生成對(duì)應(yīng)的 Map 數(shù)據(jù)結(jié)構(gòu):
/**
* 菜單相關(guān)
* 這里是單獨(dú)放到了 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]))
// 遞歸方法,平化菜單數(shù)據(jù)
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
}
},
}
})使用的時(shí)候
import {useMenuStore, useProjectStore} from "./pinia";
const storeMenu = useMenuStore()
// 當(dāng)執(zhí)行下面的操作時(shí)就會(huì)補(bǔ)全 storeMenu.flatMenuArray 和 storeMenu.flatMenuPathNameMap
storeMenu.generateMenuArrayAndMap()路由樹(shù)的基礎(chǔ)數(shù)據(jù)是這樣的:

平化后的路由數(shù)組是這樣的:

最終生成的 Map 數(shù)據(jù)是這樣的:

2. 拆分當(dāng)前路由 path,并匹配
比如當(dāng)前路由是 /system/normal-setup/auto-login,把它通過(guò) / 拆分之后就是這樣的結(jié)果
import {useRoute} from "vue-router";
const route = useRoute()
let routeSectionArray = route.path.split('/').filter(item => item !== '')
// 這樣拆分之后,前面會(huì)多出一個(gè)空白的 "" ,所以這里剔除了它
接下來(lái)要做的就是通過(guò)上面的 routerSectionArray 生成下面的幾個(gè)路由組合,再去之前生成的 Map 中匹配對(duì)應(yīng)的路由名即可
/system/system/normal-setup/system/normal-setup/auto-login
匹配之后就是這樣的結(jié)果
/system系統(tǒng)配置/system/normal-setup- 基礎(chǔ)配置
/system/normal-setup/auto-login自動(dòng)登錄
代碼是這樣的:
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})
}
})
})四、搭配其它組件構(gòu)建頁(yè)面
弄好上面的 BreadCrumb 組件之后,就可以不用再管它內(nèi)部的內(nèi)容了,它會(huì)自動(dòng)根據(jù)當(dāng)前路由值生成對(duì)應(yīng)的內(nèi)容。
這樣我們就可以放心的把它放到頁(yè)面結(jié)構(gòu)中了。
比如我的頁(yè)面主要結(jié)構(gòu)是這樣的:

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: '/' }">主頁(yè)</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>實(shí)際頁(yè)面中使用時(shí)這樣:
<template>
<Container>
<Toolbar>
<template #left>
</template>
<template #center>
</template>
<template #right>
</template>
</Toolbar>
<Content>
</Content>
</Container>
<template>五、結(jié)果

到此這篇關(guān)于vue 如何做一個(gè)動(dòng)態(tài)的 BreadCrumb 組件,el-breadcrumb ElementUI的文章就介紹到這了,更多相關(guān)vue動(dòng)態(tài)的 BreadCrumb 組件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決vue-cli webpack打包后加載資源的路徑問(wèn)題
今天小編就為大家分享一篇解決vue-cli webpack打包后加載資源的路徑問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
vue 重塑數(shù)組之修改數(shù)組指定index的值操作
這篇文章主要介紹了vue 重塑數(shù)組之修改數(shù)組指定index的值操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08
vite+vue3+ts項(xiàng)目中提示無(wú)法找到模塊的問(wèn)題及解決
這篇文章主要介紹了vite+vue3+ts項(xiàng)目中提示無(wú)法找到模塊的問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
Vue實(shí)現(xiàn)簡(jiǎn)單選項(xiàng)卡效果
這篇文章主要為大家詳細(xì)介紹了Vue實(shí)現(xiàn)簡(jiǎn)單選項(xiàng)卡效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
Vue如何使用Promise.all()方法并行執(zhí)行多個(gè)請(qǐng)求
在Vue中,可以使用Promise.all()方法并行執(zhí)行多個(gè)異步請(qǐng)求,當(dāng)所有請(qǐng)求都成功返回時(shí),Promise.all()將返回一個(gè)包含所有請(qǐng)求結(jié)果的數(shù)組,如果其中任何一個(gè)請(qǐng)求失敗,則會(huì)觸發(fā)catch()方法并返回錯(cuò)誤信息,這種方式可以顯著提高程序的性能和響應(yīng)速度2025-01-01
在vue中根據(jù)光標(biāo)的顯示與消失實(shí)現(xiàn)下拉列表
這篇文章主要介紹了在vue中根據(jù)光標(biāo)的顯示與消失實(shí)現(xiàn)下拉列表,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09

