vue3+element?plus實(shí)現(xiàn)側(cè)邊欄過(guò)程
一般前端項(xiàng)目少不了側(cè)邊欄。
如圖所示

這些鬼東西特別繁瑣,所以我們喜歡找些現(xiàn)成、開源的所謂后臺(tái)管理的前端框架,開箱即用。
方便是方便,而且做得還挺好,問(wèn)題是,有學(xué)習(xí)成本,要按照它的規(guī)則行事。一些功能是怎么實(shí)現(xiàn)的,不清楚,除非研究它的源代碼。
想改的話,更不容易。一切都靠猜、盲測(cè),一則不好改,二則出了問(wèn)題也不知道是哪里的毛病,反而欲速則不達(dá)。
所以我們之前基于一個(gè)空白的vue項(xiàng)目開發(fā),把需要的路由、ajax封裝等摞上去?,F(xiàn)在是實(shí)現(xiàn)側(cè)邊欄菜單。點(diǎn)擊左側(cè)菜單項(xiàng),對(duì)應(yīng)頁(yè)面展示在右側(cè)。
下面是詳細(xì)介紹,ui框架采用element plus。
1、如何編寫側(cè)邊欄結(jié)構(gòu)頁(yè)面
html代碼其實(shí)簡(jiǎn)單,左側(cè)菜單用<el-menu>,右側(cè)展示使用<router-view>。
后者不用做啥設(shè)置,點(diǎn)擊菜單項(xiàng),結(jié)果自然就展示在右側(cè)了。好神奇。
以下是一個(gè)包含側(cè)邊欄的頁(yè)面示例。支持二級(jí)菜單。
三級(jí)或更多就不行了。
<template>
<el-container>
<el-aside width="255px"> <!-- 側(cè)邊欄寬255px -->
<!-- router是關(guān)鍵屬性 -->
<el-menu
router
:default-active="to"
active-text-color="#ffd04b"
background-color="#001529"
text-color="#999"
class="el-menu-vertical-demo sliderHeight"
>
<!-- 如果菜單項(xiàng)存在子孫節(jié)點(diǎn),使用el-sub-menu -->
<el-sub-menu v-if="item.children" :index="item.route">
<template #title>
<el-icon><component :is="item.icon"></component></el-icon>{{ item.text }}
</template>
<el-menu-item
v-for="item2 in item.children"
:key="item2.name"
:index="item2.route"
>
<template #title>
<el-icon><component :is="item2.icon"></component></el-icon
>{{ item2.text }}
</template>
</el-menu-item>
</el-sub-menu>
<!-- 否則使用el-menu-item -->
<el-menu-item v-else :index="item.route">
<template #title>
<el-icon><component :is="item.icon"></component></el-icon>{{ item.text }}
</template>
</el-menu-item>
</el-menu>
</el-aside>
<el-main>
<!-- 結(jié)果展示在這里 -->
<router-view></router-view>
</el-main>
</el-container>
</template>
2、默認(rèn)選中菜單及加載對(duì)應(yīng)頁(yè)面
很自然地,打開包含側(cè)邊欄結(jié)構(gòu)的頁(yè)面,應(yīng)該有一個(gè)菜單項(xiàng)默認(rèn)被選中,同時(shí)加載對(duì)應(yīng)的頁(yè)面。
但是element plus只提供了選中指定菜單功能,加載頁(yè)面需要自己完成。

1)默認(rèn)選中指定的菜單項(xiàng)
設(shè)置屬性el-menu.default-active。
屬性值是el-sub-menu.index或el-menu-item.index
<el-menu
router
:default-active="to"
active-text-color="#ffd04b"
background-color="#001529"
text-color="#999"
class="el-menu-vertical-demo sliderHeight"
>
<el-menu-item :index="item.route">
2)加載對(duì)應(yīng)頁(yè)面
elment plus只能設(shè)置選中菜單項(xiàng),加載相應(yīng)頁(yè)面需要自己動(dòng)手。
import { useRouter } from "vue-router";
const router = useRouter();
const gotoDefaultPage = (menus) => {
if (menus && menus.length > 0) {
const path = router.currentRoute.value.path;
//如果當(dāng)前路徑是子菜單,則直接打開子菜單;否則打開第一個(gè)子菜單
//頁(yè)面中,使用了菜單項(xiàng)的route作為index
const to = path.split("/").length > 2 ? path : menus[0].route;
router.replace(to);
}
};
onMounted(() => {
const menus = getMenus();
gotoDefaultPage(menus);
});
3、刷新頁(yè)面
好像刷新頁(yè)面,選中啥的會(huì)丟失,頁(yè)面一片空白?這個(gè)問(wèn)題記得不是很清楚了,現(xiàn)在我沒有這個(gè)問(wèn)題。
可能是獲取到當(dāng)前路由,按照路由重新打開。代碼見2。
const path = router.currentRoute.value.path;
//如果當(dāng)前路徑是子菜單,則直接打開子菜單;否則打開第一個(gè)子菜單
//頁(yè)面中,使用了菜單項(xiàng)的route作為index
const to = path.split("/").length > 2 ? path : menus[0].route;
router.replace(to);
4、icon

每個(gè)菜單項(xiàng)前面有個(gè)小圖標(biāo)。圖標(biāo)應(yīng)該在菜單項(xiàng)/路由表二合一的數(shù)據(jù)中定義。取值從elment plus的icon中選取。
- 數(shù)據(jù)結(jié)構(gòu)
{
path: "p3-1",
name: "p3-1",
component: () => import("../views/module3/page1"),
meta: {
text: "頁(yè)面A",
icon: "Histogram",
},
},
- 頁(yè)面
<el-menu-item :index="item.route">
<template #title>
<el-icon>
<!-- 關(guān)鍵的一句 -->
<component :is="item.icon"></component>
</el-icon>{{ item.text }}
</template>
</el-menu-item>
因?yàn)榭梢允褂萌我獾膃lement plus的icon,所以索性全局注冊(cè)
- src/main.js
import { createApp } from "vue";
import App from "./App.vue";
。。。
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import * as ElIcons from "@element-plus/icons-vue";
const app = createApp(App);
app.use(ElementPlus).mount("#app");
for (const name in ElIcons) {
app.component(name, ElIcons[name]);
}
5、新開窗口
在側(cè)邊欄結(jié)構(gòu)頁(yè)面中,如何打開一個(gè)新窗口呢?
其實(shí),無(wú)論是在普通頁(yè)面,還是這種側(cè)邊欄結(jié)構(gòu)頁(yè)面,點(diǎn)擊一個(gè)鏈接或按鈕,打開一個(gè)新窗口,代碼都是一樣的。
但是!里面用到了路由。
如果該路由沒有注冊(cè),那么在本文所示的側(cè)邊欄結(jié)構(gòu)頁(yè)面中,打開新窗口會(huì)失敗,頁(yè)面仍然顯示在右側(cè),沒有新開窗口!
這一度讓我很困惑,以為<router-view>需要給個(gè)name,然而并沒有什么卵用。
按照本文所示的例子,側(cè)邊欄結(jié)構(gòu)頁(yè)面實(shí)際上有2個(gè)<router-view>。
一個(gè)是app.vue里設(shè)置了,然后側(cè)邊欄結(jié)構(gòu)頁(yè)面實(shí)際上是包含在外面這個(gè)<router-view>中,然后它自己也有一個(gè)<router-view>。
兩個(gè)都沒有命名,那么都叫“default”??赡芟到y(tǒng)采取了就近原則,在側(cè)邊欄結(jié)構(gòu)頁(yè)面中點(diǎn)擊新窗口鏈接,永遠(yuǎn)都對(duì)應(yīng)它本身這個(gè)<router-view>。
然而在定義路由項(xiàng)中,使用components,指定名稱,不好使,一點(diǎn)用沒有。后來(lái)我才發(fā)現(xiàn),新開窗口的鏈接,或者說(shuō)是路由,一定要注冊(cè),這樣就能新開窗口了。
- 新開窗口的代碼:
<template>
<div @click="browseIt(1000)" class="show-detail">打開明細(xì)頁(yè)</div>
<div>
<router-link target="_blank" to="p2-1/detail/999"
>第一種新窗口打開頁(yè)面</router-link
>
</div>
</template>
<script>
import { reactive } from "vue";
import { useRouter } from "vue-router"; //引入useRouter
export default {
setup() {
const router = useRouter();
const browseIt = (id) => {
const to = router.resolve({
name: "p2-1-detail", //這里是跳轉(zhuǎn)頁(yè)面的name,要與路由設(shè)置保持一致
params: { id: id },
});
window.open(to.href, "_blank");
};
return {
browseIt,
};
},
};
</script>
- 路由
{
path: "p2-1/detail/:id",
name: "p2-1-detail",
component: () => import("../views/module2/page-1-detail.vue"),
meta: {
text: "頁(yè)面一明細(xì)",
noList: true,
},
},
6、無(wú)限級(jí)菜單
前面的例子,菜單級(jí)別只能去到二級(jí)。如果要實(shí)現(xiàn)無(wú)限級(jí),需要使用遞歸。頁(yè)面組件遞歸。
代碼如下:
- 整體的側(cè)邊欄結(jié)構(gòu)頁(yè)面:
<template>
<el-container>
<el-aside width="255px">
<el-menu
router
:default-active="to"
active-text-color="#ffd04b"
background-color="#001529"
text-color="#999"
class="el-menu-vertical-demo sliderHeight"
>
<template v-for="item in menus" :key="item.name">
<!-- 自定義的菜單組件 -->
<middle-menu :item="item"></middle-menu>
</template>
</el-menu>
</el-aside>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</template>
<script>
import MiddleMenu from "./SidebarMenu.vue";
</script>
- 自定義的菜單組件
<template>
<el-sub-menu v-if="item.children" :index="item.route">
<template #title>
<el-icon><component :is="item.icon"></component></el-icon
>{{ item.text }}</template
>
<template v-for="innerItem in item.children" :key="innerItem.name">
<!-- 遞歸 -->
<middle-menu :item="innerItem"></middle-menu>
</template>
</el-sub-menu>
<el-menu-item v-else :index="item.route">
<template #title>
<el-icon><component :is="item.icon"></component></el-icon>{{ item.text }}
</template>
</el-menu-item>
</template>
<script>
import { defineComponent } from "vue";
export default defineComponent({
name: "middle-menu",
props: {
item: {
type: Object,
required: true,
},
},
});
</script>
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
一文詳解Vue中渲染器的簡(jiǎn)單實(shí)現(xiàn)
渲染器用于完成渲染操作,比如在瀏覽器平臺(tái)上渲染器可以將虛擬DOM轉(zhuǎn)換為真實(shí)DOM,本文將通過(guò)一個(gè)簡(jiǎn)單例子來(lái)帶大家理解Vue中渲染器的工作過(guò)程,并通過(guò)代碼示例講解的非常詳細(xì),需要的朋友可以參考下2024-05-05
vue.js實(shí)現(xiàn)請(qǐng)求數(shù)據(jù)的方法示例
這篇文章主要給大家介紹了vue.js實(shí)現(xiàn)請(qǐng)求數(shù)據(jù)的方法示例,文中分別介紹了vue1.0和vue2.0的示例方法,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-02-02
element-ui中el-row中設(shè)置:gutter間隔不生效問(wèn)題
這篇文章主要介紹了element-ui中el-row中設(shè)置:gutter間隔不生效問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
Vue實(shí)現(xiàn)的父組件向子組件傳值功能示例
這篇文章主要介紹了Vue實(shí)現(xiàn)的父組件向子組件傳值功能,結(jié)合完整實(shí)例形式簡(jiǎn)單分析了vue.js組件傳值的相關(guān)操作技巧,需要的朋友可以參考下2019-01-01
如何利用vue實(shí)現(xiàn)登陸界面及其跳轉(zhuǎn)詳解
在開發(fā)中我們經(jīng)常遇到這樣的需求,需要用戶直接點(diǎn)擊一個(gè)鏈接進(jìn)入到一個(gè)頁(yè)面,下面這篇文章主要給大家介紹了關(guān)于如何利用vue實(shí)現(xiàn)登陸界面及其跳轉(zhuǎn)的相關(guān)資料,需要的朋友可以參考下2023-04-04
WebStorm啟動(dòng)vue項(xiàng)目報(bào)錯(cuò)代碼:1080?throw?err解決辦法
在使用webstorm新建vue項(xiàng)目時(shí)常會(huì)遇到一些報(bào)錯(cuò),下面這篇文章主要給大家介紹了關(guān)于WebStorm啟動(dòng)vue項(xiàng)目報(bào)錯(cuò)代碼:1080?throw?err的解決辦法,文中將解決辦法介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12

