Element-UI結(jié)合遞歸組件實(shí)現(xiàn)后臺(tái)管理系統(tǒng)左側(cè)菜單
在 Vue.js 中,允許你編寫(xiě)一個(gè)組件來(lái)表示一個(gè)節(jié)點(diǎn),而這個(gè)節(jié)點(diǎn)可以包含多個(gè)子節(jié)點(diǎn),每個(gè)子節(jié)點(diǎn)又可以是同樣的組件。這種方式使得組件能夠處理無(wú)限層級(jí)的嵌套結(jié)構(gòu)。
應(yīng)用場(chǎng)景
遞歸組件非常適合處理具有層級(jí)結(jié)構(gòu)的數(shù)據(jù),以下是幾種常見(jiàn)的應(yīng)用場(chǎng)景:
- 多級(jí)菜單:如上所示,遞歸組件可以用來(lái)生成多級(jí)菜單,無(wú)論是水平還是垂直布局。
- 文件目錄樹(shù):文件系統(tǒng)中的目錄結(jié)構(gòu)通常是樹(shù)狀的,遞歸組件可以幫助你輕松地構(gòu)建一個(gè)文件目錄樹(shù)。
- 評(píng)論系統(tǒng):許多網(wǎng)站的評(píng)論系統(tǒng)支持回復(fù)評(píng)論,形成一個(gè)樹(shù)形結(jié)構(gòu),遞歸組件可以用來(lái)展示這些評(píng)論及其回復(fù)。
- 組織架構(gòu)圖:公司內(nèi)部的組織結(jié)構(gòu)也可以用遞歸組件來(lái)表示,每個(gè)部門(mén)下面可以有子部門(mén)或員工。
- 任務(wù)列表:在項(xiàng)目管理工具中,任務(wù)列表往往包含父任務(wù)和子任務(wù),遞歸組件可以清晰地展現(xiàn)這種層次關(guān)系。
實(shí)現(xiàn)步驟
1. 安裝 Element-UI
確保你的項(xiàng)目已經(jīng)安裝了 Element-UI。如果還沒(méi)有安裝,可以通過(guò) npm 或 yarn 來(lái)安裝:
npm install element-ui --save # 或者 yarn add element-ui
然后在 main.js 文件中引入并使用 Element-UI:
import Vue from 'vue'; import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI);
2. 設(shè)計(jì)菜單數(shù)據(jù)結(jié)構(gòu)
先定義一個(gè)合理的菜單數(shù)據(jù)結(jié)構(gòu),通常是一個(gè)數(shù)組對(duì)象,其中每個(gè)對(duì)象代表一個(gè)菜單項(xiàng),并且可以包含子菜單。例如:
import Layout from '@/Layout/index.vue'
export const routes = [
{
path: '/',
name: 'redirect',
component: Layout,
hidden: true, // 隱藏菜單
redirect: "/homePage", // 用戶在地址欄輸入 '/' 時(shí)會(huì)自動(dòng)重定向到 /homePage 頁(yè)面
},
{
path: '/homePage',
component: Layout,
redirect: "/homePage/index",
meta: {
title: "首頁(yè)",
},
children: [
{
path: 'index',
name: 'homePageIndex',
meta: {
title: "首頁(yè)",
},
component: () => import('@/views/homePage/index.vue')
}
]
},
{
path: '/login',
component: () => import('@/views/login.vue'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/error/404.vue'),
hidden: true
},
{
path: '/401',
component: () => import('@/views/error/401.vue'),
hidden: true
},
{
path: '/admin',
meta: {
title: "系統(tǒng)管理",
},
component: Layout,
children: [
{
path: 'user',
name: 'userIndex',
meta: {
title: "用戶管理",
},
component: () => import('@/views/admin/user.vue')
},
{
path: 'role',
name: 'roleIndex',
meta: {
title: "權(quán)限管理",
},
component: () => import('@/views/admin/role.vue'),
children: [
{
path: 'add',
name: 'addRole',
hidden: true,
meta: {
title: "添加角色",
},
component: () => import('@/views/admin/user/index.vue')
},
{
path: 'update',
name: 'updateRole',
hidden: true,
meta: {
title: "編輯角色",
},
component: () => import('@/views/admin/role/index.vue')
}
]
}
]
},
{
path: '/tableEcho',
meta: {
title: "表格管理",
},
component: Layout,
children: [
{
path: 'test',
name: 'tableEchoIndex',
meta: {
title: "表格測(cè)試",
},
component: () => import('@/views/tableEcho/index.vue'),
children: [
{
path: 'add',
name: 'addTable',
hidden: true,
meta: {
title: "新增測(cè)試",
},
component: () => import('@/views/tableEcho/add.vue')
}
]
},
],
},
]
上述示例:
- 配置了四個(gè)路由器:根路徑重定向、首頁(yè)、系統(tǒng)管理、表格管理。
- 根路徑重定向: 訪問(wèn)根路徑
'/'時(shí),會(huì)自動(dòng)重定向到/homePage。 - 首頁(yè)菜單: 一個(gè)子菜單。
- 系統(tǒng)管理: 兩個(gè)子菜單, 兩個(gè)三級(jí)菜單(不展示)。
- 表格管理: 一個(gè)子菜單, 一個(gè)三級(jí)菜單(不展示)。
注意點(diǎn):
每個(gè)菜單的一級(jí)路由的
component都必須是Layout組件,Layout組件用于定義整個(gè)系統(tǒng)頁(yè)面的基本結(jié)構(gòu)和布局,比如導(dǎo)航欄、側(cè)邊欄等。通過(guò)將所有的一級(jí)路由都指向Layout組件,可以確保無(wú)論用戶訪問(wèn)哪個(gè)頁(yè)面,都能看到一致的布局。
Layout 組件文件布局圖片如下

3. 創(chuàng)建遞歸組件
創(chuàng)建一個(gè)遞歸組件來(lái)渲染菜單項(xiàng)。這個(gè)組件將根據(jù)傳入的數(shù)據(jù)結(jié)構(gòu)遞歸地生成菜單項(xiàng)。
Sidebar / SidebarItem.vue
<div class="sidebar_item">
<!-- 如果沒(méi)有子菜單或只有一個(gè)二級(jí)的子菜單則直接渲染 -->
<template
v-if="hasOneShowingChild(item.children, item) && (!onlyOneChild.children || onlyOneChild.noShowingChildren)"
class="item">
<router-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
<el-menu-item :index="resolvePath(onlyOneChild.path)" class="title">
<img src="" alt="">
<span slot="title">{{ onlyOneChild.meta.title }}</span>
</el-menu-item>
</router-link>
</template>
<!-- 有子菜單 -->
<el-submenu v-else :index="resolvePath(item.path)" popper-append-to-body>
<template slot="title">
<span slot="title" class="title">{{ item.meta.title }}</span>
</template>
<Sidebar-item v-for="child in item.children" :key="child.path" :is-nest="true" :item="child"
:base-path="resolvePath(child.path)"></Sidebar-item>
</el-submenu>
</div>
</template>
<script>
import path from "path";
export default {
name: "SidebarItem",
data() {
return {
onlyOneChild: {
children: [],
},
}
},
props: {
item: {
type: Object,
required: true
},
basePath: {
type: String,
default: ''
}
},
methods: {
// 判斷是否只有一個(gè)子菜單
hasOneShowingChild(children = [], parent) {
// console.log('parent::: ',children , parent);
if (!children) {
children = [];
}
// 過(guò)濾掉隱藏的菜單
const showingChildren = children.filter((item) => {
// 是否隱藏菜單
if (item.hidden) {
return false;
} else {
this.onlyOneChild = item;
return true;
}
});
// 當(dāng)只有一個(gè)子路由時(shí),默認(rèn)顯示子路由器
if (showingChildren.length === 1) {
return true;
}
// 如果沒(méi)有子路由,則顯示父級(jí)路由
if (showingChildren.length === 0) {
this.onlyOneChild = { ...parent, path: "", noShowingChildren: true };
return true;
}
return false;
},
// 判斷是否是外鏈
isExternal(path) {
return /^(https?:|mailto:|tel:)/.test(path);
},
// 路徑拼接
resolvePath(routePath) {
if (this.isExternal(routePath)) {
return routePath;
}
if (this.isExternal(this.basePath)) {
return this.basePath;
}
return path.resolve(this.basePath, routePath);
},
}
}
</script>
<style lang="scss" scoped>
.sidebar_item {
cursor: pointer;
>a {
height: 60px;
line-height: 60px;
}
}
::v-deep .el-submenu__title {
height: 60px;
line-height: 60px;
}
::v-deep .el-submenu__title:hover,
a :hover {
background-color: #2a9cff !important;
}
::v-deep .active {
background-color: #2a9cff !important;
}
.is-active {
background-color: #2a9cff !important;
}
.title {
font-size: 16px;
}
</style>
注意:
代碼里導(dǎo)入的
path模塊需要安裝 node-polyfill-webpack-plugin 模塊, 原因是由于 webpack5 中移除了nodejs核心模塊的polyfill自動(dòng)引入, 所以需要下載插件手動(dòng)引入
npm install node-polyfill-webpack-plugin --save # 或者 yarn add node-polyfill-webpack-plugin
vue.config.js 配置
const { defineConfig } = require('@vue/cli-service');
const nodePolyfillWebpackPlugin = require("node-polyfill-webpack-plugin");
module.exports = defineConfig({
configureWebpack: (config) => {
// 由于webpack5中移除了nodejs核心模塊的polyfill自動(dòng)引入, 所以需要下載插件手動(dòng)引入
config.plugins.push(new nodePolyfillWebpackPlugin());
}
})
4. 使用遞歸組件
在主布局或需要顯示菜單的地方使用 Menu 組件,并傳遞菜單數(shù)據(jù):
Sidebar / index.vue
<template>
<div style="padding-top: 30px;">
<!-- 左側(cè)菜單 -->
<el-menu :default-active="index" class="memu" @open="handleOpen" @close="handleClose" background-color="#304156"
text-color="#bfcbd9" active-text-color="#fff" @select="handleSelect">
<Sidebar-item v-for="route in sidebarRouters" :key="route.path + index" :item="route" :base-path="route.path" />
</el-menu>
</div>
</template>
<script>
import SidebarItem from './SidebarItem.vue';
import { mapGetters } from "vuex";
export default {
name: 'Sidebar',
data() {
return {
index: this.$route.path,
}
},
components: { SidebarItem },
computed: {
...mapGetters(["sidebarRouters"]),
},
methods: {
handleOpen(key, keyPath) {
console.log('handleOpen::: ', key, keyPath);
},
handleClose(key, keyPath) {
console.log('handleClose::: ', key, keyPath);
},
handleSelect(index, indexPath) {
console.log('handleSelect::: ', index, indexPath);
}
}
}
</script>
<style lang="scss" scoped>
.memu {
display: inline-block;
text-align: left;
width: 100%;
}
</style>
實(shí)現(xiàn)效果

總結(jié)
Element-UI 結(jié)合遞歸組件的方式,用于構(gòu)建后臺(tái)管理系統(tǒng)的左側(cè)菜單,主要是通過(guò)以下步驟實(shí)現(xiàn)的:
配置路由(Routes): 首先,如同前述代碼片段所示,定義一系列路由對(duì)象構(gòu)成的數(shù)組 routes,這些對(duì)象不僅描述了各頁(yè)面路徑(path)、頁(yè)面名稱(chēng)(name)、對(duì)應(yīng)組件(component),還包括了嵌套的子路由(children)以及元信息(如頁(yè)面標(biāo)題)等,從而形成了多級(jí)菜單的結(jié)構(gòu)基礎(chǔ)。
遞歸組件(Recursive Component): 利用 Vue 中的遞歸組件技術(shù),創(chuàng)建一個(gè)菜單組件,該組件根據(jù)傳入的路由配置(通常是 routes 數(shù)組)自動(dòng)生成菜單項(xiàng)。遞歸的邏輯在于:組件內(nèi)根據(jù)當(dāng)前路由的 children 屬性判斷是否有子菜單,如果有,則繼續(xù)渲染子菜單組件,直至沒(méi)有更多子節(jié)點(diǎn),以此實(shí)現(xiàn)無(wú)限級(jí)菜單的展現(xiàn)。
Element-UI 風(fēng)格: 在實(shí)現(xiàn)遞歸菜單組件時(shí),利用 Element-UI 的 UI 組件庫(kù)(如 el-menu、el-submenu、el-menu-item 等),為菜單項(xiàng)賦予統(tǒng)一且美觀的樣式,實(shí)現(xiàn)折疊、展開(kāi)、激活狀態(tài)等交互效果,增強(qiáng)用戶體驗(yàn)。
總結(jié)而言,Element-UI 與遞歸組件結(jié)合的方式,使得后臺(tái)管理系統(tǒng)的左側(cè)菜單能夠高效地根據(jù)路由配置動(dòng)態(tài)渲染多層級(jí)菜單,同時(shí)確保了菜單的一致性和美觀性,提升了系統(tǒng)的可維護(hù)性和用戶體驗(yàn)。
到此這篇關(guān)于Elemnt-UI + 遞歸組件實(shí)現(xiàn)后臺(tái)管理系統(tǒng)左側(cè)菜單的文章就介紹到這了,更多相關(guān)Elemnt-UI + 遞歸組件實(shí)現(xiàn)后臺(tái)管理系統(tǒng)左側(cè)菜單內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue之保留小數(shù)點(diǎn)兩位小數(shù) 使用filters(過(guò)濾器)
這篇文章主要介紹了vue之保留小數(shù)點(diǎn)兩位小數(shù) 使用filters(過(guò)濾器),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
vue項(xiàng)目base64加解密使用方式以及解密亂碼
這篇文章主要介紹了vue項(xiàng)目base64加解密使用方式以及解密亂碼問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
Vue封裝DateRangePicker組件流程詳細(xì)介紹
在后端管理項(xiàng)目中使用vue來(lái)進(jìn)行前端項(xiàng)目的開(kāi)發(fā),但我們都知道Vue實(shí)際上無(wú)法監(jiān)聽(tīng)由第三方插件所引起的數(shù)據(jù)變化。也無(wú)法獲得JQuery這樣的js框架對(duì)元素值的修改的。而日期控件daterangepicker又基于JQuery來(lái)實(shí)現(xiàn)的2022-11-11
elementUI el-form 數(shù)據(jù)無(wú)法賦值且不報(bào)錯(cuò)解決方法
本文主要介紹了elementUI el-form 數(shù)據(jù)無(wú)法賦值且不報(bào)錯(cuò)解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-12-12
詳解Vue返回值動(dòng)態(tài)生成表單及提交數(shù)據(jù)的辦法
這篇文章主要為大家介紹了Vue返回值動(dòng)態(tài)生成表單及提交數(shù)據(jù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2021-12-12

