vue3動(dòng)態(tài)路由+菜單欄的實(shí)現(xiàn)示例
動(dòng)態(tài)路由
這里用vue3和vite來(lái)實(shí)現(xiàn)動(dòng)態(tài)路由,點(diǎn)擊這里查看效果 源碼
使用場(chǎng)景
在后臺(tái)管理系統(tǒng),可以根據(jù)登錄用戶的不同返回不同路由,頁(yè)面也會(huì)根據(jù)這些路由生成對(duì)應(yīng)的菜單。這樣通過服務(wù)器就能控制一個(gè)用戶可以訪問的內(nèi)容了。
比如管理員可以看到服務(wù)器日志,可以進(jìn)行系統(tǒng)設(shè)置,普通用戶就訪問不了這些頁(yè)面。
步驟
定義基礎(chǔ)路由表
有一些路由不需要登錄也能訪問的,比如login和404頁(yè)面,這些路由要提前在寫好并加入到router中。
編寫路由組件
所有的路由組件都要提前寫好放到/views目錄下
添加路由
定義addRoute()方法,在登錄后獲取服務(wù)器路由通過這個(gè)方法添加路由
生成菜單
路由的meta字段可以添加一些菜單相關(guān)的信息,比如菜單名、icon、排序之類的。遍歷路由列表,根據(jù)meta的信息就能生成對(duì)應(yīng)的菜單了
代碼
服務(wù)器路由數(shù)據(jù)
這里模擬服務(wù)器返回的數(shù)據(jù),為了方便只寫了一條路由,看源碼有更多示例。
meta的數(shù)據(jù)是自己定的,一定要跟后端對(duì)接好。
[
{
path: '/user',
component: 'DEFAULT_LAYOUT',
meta: {menuName: '用戶', order: 1},
children: [
{
path: 'info',
name: 'userInfo',
component: 'user/info',
meta: {menuName: '個(gè)人中心'}
}
]
}
] 注意
- 只支持二級(jí)路由,也就是子路由下不能再有子路由
- 每個(gè)一級(jí)路由至少有一個(gè)子路由,即使你只想展示一個(gè)菜單。因?yàn)楦嘎酚尚枰@示布局組件,子路由才是真正顯示內(nèi)容的地方。
- component: 'DEFAULT_LAYOUT'表示這個(gè)路由要使用的布局組件,需要提前定義好。
- meta: {menuName: '用戶', order: 1}menuName表示這個(gè)菜單的名稱,order表示菜單的排序,還可以添加其他內(nèi)容,比如
- 只有一個(gè)子路由不想生成二級(jí)菜單,就可以設(shè)置single: true
- 子路由的name,必須設(shè)置這個(gè)字段,而且整個(gè)路由中不能重復(fù),點(diǎn)擊一個(gè)菜單時(shí)需要用它來(lái)導(dǎo)航
- 子路由的component表示路由組件的位置,需要提前在/views目錄下把所有路由組件都寫好。比如這里的user/info
- 實(shí)際會(huì)導(dǎo)入import('@/views/user/info.vue')。注意:路徑之間必須用/隔開
- meta: {menuName: '個(gè)人中心'}子路由必須定義menuName,因?yàn)樽勇酚蓵?huì)生成用戶可以點(diǎn)擊的菜單,沒有名稱的話就不會(huì)顯示了
添加路由
假設(shè)現(xiàn)在登錄成功,開始調(diào)用addRoute()方法添加路由,這個(gè)方法根據(jù)情況放在自己需要的地方,這里為了演示都放在一起了。
// /components/layout.vue
import { ref } from 'vue'
import { useRouter } from 'vue-router'
// 這個(gè)布局組件需要自己提前定義好
import DEFAULT_LAYOUT from '@/components/layout.vue'
const server_route = ref([])
const addRoute = async () => {
// 如果本地沒有路由信息,就從服務(wù)器獲取
if (!server_route.value.length) {
// 這里模擬從服務(wù)器獲取數(shù)據(jù),實(shí)際需要從后端獲取數(shù)據(jù)
const { default: routes = [] } = await import('@/router/server_route')
server_route.value = routes
}
// 把路由表的component字段轉(zhuǎn)成真實(shí)的路由
server_route.value.map((_route) => {
if (_route.component === 'DEFAULT_LAYOUT') {
_route.component = DEFAULT_LAYOUT
}
const children = _route.children
// 根據(jù)字符串動(dòng)態(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ù)會(huì)保存到server_route里面,實(shí)際開發(fā)應(yīng)該保存到本地localStorage,否則刷新所有路由消失。
獲取到數(shù)據(jù)還不能用,因?yàn)閏omponent字段還是字符串,要轉(zhuǎn)成懶加載的形式導(dǎo)入組件才行。
// 把路由表的component字段轉(zhuǎn)成真實(shí)的路由
server_route.value.map((_route) => {
if (_route.component === 'DEFAULT_LAYOUT') {
// 設(shè)置布局組件,可以為項(xiàng)目設(shè)置多個(gè)布局,服務(wù)器只需要修改這里,前端就能顯示多種布局了
_route.component = DEFAULT_LAYOUT
}
const children = _route.children
// 根據(jù)字符串動(dòng)態(tài)導(dǎo)入路由組件
if (Array.isArray(children) && children?.length > 0) {
children.map((childRoute) => {
const path = childRoute.component.split('/')
// 用vite提供的動(dòng)態(tài)導(dǎo)入功能,根據(jù)字符串從views目錄下導(dǎo)入組件
// 參考:https://cn.vitejs.dev/guide/features.html#dynamic-import
if (path.length === 1) {
// 如果是單個(gè)vue文件
childRoute.component = () => import(`@/views/${path[0]}.vue`)
} else {
// 否則就是一個(gè)目錄
childRoute.component = () => import(`@/views/${path[0]}/${path[1]}.vue`)
}
})
}
}) 因?yàn)楦附M件的布局組件比較少,一般不用做懶加載全部導(dǎo)入進(jìn)來(lái),根據(jù)字符串選擇對(duì)應(yīng)的布局就行了。
子組件需要?jiǎng)討B(tài)的導(dǎo)入。vite提供了根據(jù)變量動(dòng)態(tài)導(dǎo)入模塊的方法。
如果component: 'user/info'
- 先const path = childRoute.component.split('/')拆分一下路徑,這時(shí)候path = ['user', 'info']
- 因?yàn)閕mport()根據(jù)變量導(dǎo)入只能深入一層文件,如果直接導(dǎo)入user/info,這樣會(huì)報(bào)錯(cuò),需要先拆分然后再拼起來(lái)
- 然后根據(jù)path動(dòng)態(tài)導(dǎo)入路由,并賦值給子路由的component字段。需要保證/views目錄下有這樣的組件
// 路徑必須以絕對(duì)路徑,相對(duì)路徑或@開頭,文件名結(jié)尾,vite官網(wǎng)有說明
// 不符合的話導(dǎo)入報(bào)錯(cuò)
childRoute.component = () => import(`@/views/${path[0]}/${path[1]}.vue`) 如果component: 'welcome'
- 這時(shí)候組件的路徑就等于path = ['welcome']
- 然后動(dòng)態(tài)導(dǎo)入
childRoute.component = () => import(`@/views/${path[0]}.vue`) 上面的代碼默認(rèn)子路由下面沒有子路由了,如果有很多級(jí)路由的話,需要做更多的判斷。
經(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: '個(gè)人中心'}
}
]
}
] 這樣再排序一下然后就可以直接添加到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ù),下面可以生成菜單了,這里只對(duì)server_route服務(wù)器返回的數(shù)據(jù)生成菜單,本地定義的路由不會(huì)添加到菜單里面
<!-- /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">
<!-- 顯示多級(jí)菜單-->
<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>
<!-- 只顯示一級(jí)菜單-->
<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> 上面的代碼只是演示,實(shí)際開發(fā)應(yīng)該定義一個(gè)單獨(dú)的layout-aside組件專門渲染菜單。
總結(jié)
動(dòng)態(tài)添加路由只要提前定義好服務(wù)器數(shù)據(jù),約定好格式,做起來(lái)還是很簡(jiǎn)單的。只要能根據(jù)component字段正確的導(dǎo)入組件就沒什么大問題,
不過這只是一個(gè)簡(jiǎn)單的示例,實(shí)際開發(fā)還是有很多情況要處理的。
到此這篇關(guān)于vue3動(dòng)態(tài)路由+菜單欄的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)vue3動(dòng)態(tài)路由+菜單欄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- vue3?Error:Unknown?variable?dynamic?import:?../views/的解決方案
- 前端單獨(dú)實(shí)現(xiàn)vue動(dòng)態(tài)路由的示例代碼
- Vue3動(dòng)態(tài)路由(響應(yīng)式帶參數(shù)的路由)變更頁(yè)面不刷新的問題解決辦法
- 在Vue3中實(shí)現(xiàn)動(dòng)態(tài)路由的示例代碼
- vite+vue3+tsx項(xiàng)目打包后動(dòng)態(tài)路由無(wú)法加載頁(yè)面的問題及解決
- vue3.0基于views批量實(shí)現(xiàn)動(dòng)態(tài)路由的方法(示例代碼)
相關(guān)文章
vue 修改 data 數(shù)據(jù)問題并實(shí)時(shí)顯示的方法
今天小編就為大家分享一篇vue 修改 data 數(shù)據(jù)問題并實(shí)時(shí)顯示的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2018-08-08
vue?目錄樹的展開與關(guān)閉的實(shí)現(xiàn)
Vue作為一款流行的前端框架,提供了一種數(shù)據(jù)驅(qū)動(dòng)的方式來(lái)實(shí)現(xiàn)目錄樹,本文主要介紹了vue?目錄樹的展開與關(guān)閉的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11
element table跨分頁(yè)多選及回顯的實(shí)現(xiàn)示例
本文主要介紹了element table跨分頁(yè)多選及回顯的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
vue項(xiàng)目實(shí)現(xiàn)一鍵網(wǎng)站換膚效果實(shí)例(webpack-theme-color-replacer的使用)
換皮膚一般都是點(diǎn)擊一個(gè)按鈕彈出一些皮膚的選項(xiàng),選中選項(xiàng)后皮膚生效,下面這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目實(shí)現(xiàn)一鍵網(wǎng)站換膚效果的相關(guān)資料,文中主要介紹的是webpack-theme-color-replacer的使用,需要的朋友可以參考下2023-02-02
ant-design-vue 時(shí)間選擇器賦值默認(rèn)時(shí)間的操作
這篇文章主要介紹了ant-design-vue 時(shí)間選擇器賦值默認(rèn)時(shí)間的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨過來(lái)看看吧2020-10-10
vue arco.design錨點(diǎn)Anchor使用方式
這篇文章主要介紹了vue arco.design錨點(diǎn)Anchor使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-04-04
vue ssr+koa2構(gòu)建服務(wù)端渲染的示例代碼
這篇文章主要介紹了vue ssr+koa2構(gòu)建服務(wù)端渲染的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
使用Vue Composition API寫出清晰、可擴(kuò)展的表單實(shí)現(xiàn)
這篇文章主要介紹了使用Vue Composition API寫出清晰、可擴(kuò)展的表單實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
vue內(nèi)置組件component--通過is屬性動(dòng)態(tài)渲染組件操作
這篇文章主要介紹了vue內(nèi)置組件component--通過is屬性動(dòng)態(tài)渲染組件操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2020-07-07

