vue3動態(tài)路由+菜單欄的實現(xiàn)示例
動態(tài)路由
這里用vue3和vite來實現(xiàn)動態(tài)路由,點擊這里查看效果 源碼
使用場景
在后臺管理系統(tǒng),可以根據(jù)登錄用戶的不同返回不同路由,頁面也會根據(jù)這些路由生成對應(yīng)的菜單。這樣通過服務(wù)器就能控制一個用戶可以訪問的內(nèi)容了。
比如管理員可以看到服務(wù)器日志,可以進(jìn)行系統(tǒng)設(shè)置,普通用戶就訪問不了這些頁面。
步驟
定義基礎(chǔ)路由表
有一些路由不需要登錄也能訪問的,比如login和404頁面,這些路由要提前在寫好并加入到router中。
編寫路由組件
所有的路由組件都要提前寫好放到/views目錄下
添加路由
定義addRoute()方法,在登錄后獲取服務(wù)器路由通過這個方法添加路由
生成菜單
路由的meta字段可以添加一些菜單相關(guān)的信息,比如菜單名、icon、排序之類的。遍歷路由列表,根據(jù)meta的信息就能生成對應(yīng)的菜單了
代碼
服務(wù)器路由數(shù)據(jù)
這里模擬服務(wù)器返回的數(shù)據(jù),為了方便只寫了一條路由,看源碼有更多示例。
meta的數(shù)據(jù)是自己定的,一定要跟后端對接好。
[
{
path: '/user',
component: 'DEFAULT_LAYOUT',
meta: {menuName: '用戶', order: 1},
children: [
{
path: 'info',
name: 'userInfo',
component: 'user/info',
meta: {menuName: '個人中心'}
}
]
}
] 注意
- 只支持二級路由,也就是子路由下不能再有子路由
- 每個一級路由至少有一個子路由,即使你只想展示一個菜單。因為父路由需要顯示布局組件,子路由才是真正顯示內(nèi)容的地方。
- component: 'DEFAULT_LAYOUT'表示這個路由要使用的布局組件,需要提前定義好。
- meta: {menuName: '用戶', order: 1}menuName表示這個菜單的名稱,order表示菜單的排序,還可以添加其他內(nèi)容,比如
- 只有一個子路由不想生成二級菜單,就可以設(shè)置single: true
- 子路由的name,必須設(shè)置這個字段,而且整個路由中不能重復(fù),點擊一個菜單時需要用它來導(dǎo)航
- 子路由的component表示路由組件的位置,需要提前在/views目錄下把所有路由組件都寫好。比如這里的user/info
- 實際會導(dǎo)入import('@/views/user/info.vue')。注意:路徑之間必須用/隔開
- meta: {menuName: '個人中心'}子路由必須定義menuName,因為子路由會生成用戶可以點擊的菜單,沒有名稱的話就不會顯示了
添加路由
假設(shè)現(xiàn)在登錄成功,開始調(diào)用addRoute()方法添加路由,這個方法根據(jù)情況放在自己需要的地方,這里為了演示都放在一起了。
// /components/layout.vue
import { ref } from 'vue'
import { useRouter } from 'vue-router'
// 這個布局組件需要自己提前定義好
import DEFAULT_LAYOUT from '@/components/layout.vue'
const server_route = ref([])
const addRoute = async () => {
// 如果本地沒有路由信息,就從服務(wù)器獲取
if (!server_route.value.length) {
// 這里模擬從服務(wù)器獲取數(shù)據(jù),實際需要從后端獲取數(shù)據(jù)
const { default: routes = [] } = await import('@/router/server_route')
server_route.value = routes
}
// 把路由表的component字段轉(zhuǎn)成真實的路由
server_route.value.map((_route) => {
if (_route.component === 'DEFAULT_LAYOUT') {
_route.component = DEFAULT_LAYOUT
}
const children = _route.children
// 根據(jù)字符串動態(tài)導(dǎo)入路由組件
if (Array.isArray(children) && children?.length > 0) {
children.map((childRoute) => {
const path = childRoute.component.split('/')
if (path.length === 1) {
childRoute.component = () => import(`@/views/${path}.vue`)
} else {
childRoute.component = () => import(`@/views/${path[0]}/${path[1]}.vue`)
}
})
}
})
// 排序
server_route.value.sort((a, b) => (a?.meta?.order ?? 0) - (b?.meta?.order ?? 0))
// 循環(huán)添加路由
server_route.value.map((route) => router.addRoute(route))
} 從服務(wù)器獲取到的數(shù)據(jù)會保存到server_route里面,實際開發(fā)應(yīng)該保存到本地localStorage,否則刷新所有路由消失。
獲取到數(shù)據(jù)還不能用,因為component字段還是字符串,要轉(zhuǎn)成懶加載的形式導(dǎo)入組件才行。
// 把路由表的component字段轉(zhuǎn)成真實的路由
server_route.value.map((_route) => {
if (_route.component === 'DEFAULT_LAYOUT') {
// 設(shè)置布局組件,可以為項目設(shè)置多個布局,服務(wù)器只需要修改這里,前端就能顯示多種布局了
_route.component = DEFAULT_LAYOUT
}
const children = _route.children
// 根據(jù)字符串動態(tài)導(dǎo)入路由組件
if (Array.isArray(children) && children?.length > 0) {
children.map((childRoute) => {
const path = childRoute.component.split('/')
// 用vite提供的動態(tài)導(dǎo)入功能,根據(jù)字符串從views目錄下導(dǎo)入組件
// 參考:https://cn.vitejs.dev/guide/features.html#dynamic-import
if (path.length === 1) {
// 如果是單個vue文件
childRoute.component = () => import(`@/views/${path[0]}.vue`)
} else {
// 否則就是一個目錄
childRoute.component = () => import(`@/views/${path[0]}/${path[1]}.vue`)
}
})
}
}) 因為父組件的布局組件比較少,一般不用做懶加載全部導(dǎo)入進(jìn)來,根據(jù)字符串選擇對應(yīng)的布局就行了。
子組件需要動態(tài)的導(dǎo)入。vite提供了根據(jù)變量動態(tài)導(dǎo)入模塊的方法。
如果component: 'user/info'
- 先const path = childRoute.component.split('/')拆分一下路徑,這時候path = ['user', 'info']
- 因為import()根據(jù)變量導(dǎo)入只能深入一層文件,如果直接導(dǎo)入user/info,這樣會報錯,需要先拆分然后再拼起來
- 然后根據(jù)path動態(tài)導(dǎo)入路由,并賦值給子路由的component字段。需要保證/views目錄下有這樣的組件
// 路徑必須以絕對路徑,相對路徑或@開頭,文件名結(jié)尾,vite官網(wǎng)有說明
// 不符合的話導(dǎo)入報錯
childRoute.component = () => import(`@/views/${path[0]}/${path[1]}.vue`) 如果component: 'welcome'
- 這時候組件的路徑就等于path = ['welcome']
- 然后動態(tài)導(dǎo)入
childRoute.component = () => import(`@/views/${path[0]}.vue`) 上面的代碼默認(rèn)子路由下面沒有子路由了,如果有很多級路由的話,需要做更多的判斷。
經(jīng)過轉(zhuǎn)換已經(jīng)把component轉(zhuǎn)成真正的組件了,轉(zhuǎn)換后的server_route
import DEFAULT_LAYOUT from '@/components/layout.vue'
server_route.value = [
{
path: '/user',
component: DEFAULT_LAYOUT,
meta: {menuName: '用戶', order: 1},
children: [
{
path: 'info',
name: 'userInfo',
component: () => import('@/views/user/info.vue'),
meta: {menuName: '個人中心'}
}
]
}
] 這樣再排序一下然后就可以直接添加到router里面了
import { useRouter } from 'vue-router'
const router = useRouter()
// 排序
server_route.value.sort((a, b) => (a?.meta?.order ?? 0) - (b?.meta?.order ?? 0))
// 遍歷轉(zhuǎn)換好的路由表,添加路由
server_route.value.map((_route) => router.addRoute(_route)) 生成菜單
有了路由數(shù)據(jù),下面可以生成菜單了,這里只對server_route服務(wù)器返回的數(shù)據(jù)生成菜單,本地定義的路由不會添加到菜單里面
<!-- /components/layout.vue -->
<template>
<div>
<nav>
<h1>菜單欄</h1>
<div style="display: flex; gap: 50px; align-items: flex-end;">
<template v-for="menu in server_route">
<!-- 顯示多級菜單-->
<div v-if="!menu.meta.single">
<h5>{{ menu.meta.menuName }}</h5>
<button
v-for="child in menu.children"
@click="router.push({name: child.name})">
{{ child.meta.menuName }}
</button>
</div>
<!-- 只顯示一級菜單-->
<div v-else>
<button @click="router.push({name: menu.children[0].name})">{{ menu.children[0].meta.menuName }}</button>
</div>
</template>
</div>
</nav>
<hr>
<button v-show="needAddRoutes" @click="login">模擬登錄獲取路由</button>
<main>
<router-view />
</main>
</div>
</template> 上面的代碼只是演示,實際開發(fā)應(yīng)該定義一個單獨的layout-aside組件專門渲染菜單。
總結(jié)
動態(tài)添加路由只要提前定義好服務(wù)器數(shù)據(jù),約定好格式,做起來還是很簡單的。只要能根據(jù)component字段正確的導(dǎo)入組件就沒什么大問題,
不過這只是一個簡單的示例,實際開發(fā)還是有很多情況要處理的。
到此這篇關(guān)于vue3動態(tài)路由+菜單欄的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)vue3動態(tài)路由+菜單欄內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
詳解Vue 2中的? initState 狀態(tài)初始化
這篇文章主要介紹了詳解Vue 2中的initState狀態(tài)初始化,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下2022-08-08
基于Vue3+Node.js實現(xiàn)客服實時聊天功能
想象一下淘寶客服的聊天窗口:你發(fā)消息,客服立刻就能看到并回復(fù),這種即時通訊效果是如何實現(xiàn)的呢?本文我們使用 Vue3 作為前端框架,Node.js 作為后端,通過 WebSocket+ Socket.IO 協(xié)議實現(xiàn)實時通信,需要的朋友可以參考下2025-05-05
Vue如何使用ElementUI對表單元素進(jìn)行自定義校驗及踩坑
有一些驗證不是通過input select這樣的受控組件來觸發(fā)驗證條件的 ,可以通過自定義驗證的方法來觸發(fā),下面這篇文章主要給大家介紹了關(guān)于Vue如何使用ElementUI對表單元素進(jìn)行自定義校驗及踩坑的相關(guān)資料,需要的朋友可以參考下2023-02-02
通過vue-router懶加載解決首次加載時資源過多導(dǎo)致的速度緩慢問題
這篇文章主要介紹了vue-router懶加載解決首次加載時資源過多導(dǎo)致的速度緩慢問題,文中單獨給大家介紹了vue router路由懶加載問題,需要的朋友可以參考下2018-04-04
基于Vue實現(xiàn)的多條件篩選功能的詳解(類似京東和淘寶功能)
這篇文章主要介紹了Vue多條件篩選功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05

