vite+vue3+pinia實現(xiàn)動態(tài)注冊懶加載路由教程
模塊版本
- vite:^5.4.10
- vue:^3.5.12
- vue-router:^4.4.5
- pinia:^2.2.6
- pinia-plugin-persistedstate:^4.1.3(pinia持久化插件)
業(yè)務(wù)需求說明
每個程序都要滿足不同的業(yè)務(wù)需求,以下代碼只是滿足我當(dāng)前的業(yè)務(wù)需求
- 后端保存了每個用戶的前端路由列表信息
- 前端默認(rèn)路徑為’/login’,比如www.xxxx.com訪問默認(rèn)顯示login頁面
- 前端默認(rèn)注冊靜態(tài)路由’/login’,并重定向到路徑’/’
- 用戶點擊登錄后獲取路由列表,通過addRoute注冊路由
router代碼
import {createRouter, createWebHistory} from 'vue-router'
import type {Router} from 'vue-router'
const router: Router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
component: () => import('@/views/Login.vue')
},
{
path: '/login',
name: 'login',
meta: {
navBar: false,
token: false
},
component: () => import('@/views/Login.vue')
}
],
})
export default routerLogin頁面(ts+setup)
<script lang="ts" setup>
import {ref} from "vue"
import {useRouter} from 'vue-router'
import {loginApi} from '@/api/login/loginApi'
import {useUserInfo, useMyToken} from '@/stores/counter'
import type {RouterListItem} from '@/types/login'
const userInfo = useUserInfo()
const myToken = useMyToken()
const router = useRouter()
/** 用戶輸入賬號 */
const userName = ref<string>('')
/** 用戶輸入的密碼 */
const password = ref<string>('')
/** 登錄API */
const logon = async () => {
/** 發(fā)送登錄請求,攜帶用戶賬號和密碼信息 */
loginApi(userName.value, password.value).then((res) => {
/** 后端返回的用戶信息和路由列表,寫入pinia */
userInfo.setUserInfo(res.result.info)
/** 用戶token信息,寫入pinia */
myToken.setMyToken(res.result.token)
/** 調(diào)取pinia內(nèi)的方法注冊路由 */
userInfo.registeredRoute()
/** 由于后端返回的路由列表是JSON格式,需要轉(zhuǎn)換 */
let routerListArr: RouterListItem[] = []
if (userInfo.userInfo !== undefined) {
/** 轉(zhuǎn)換路由信息 */
routerListArr = JSON.parse(userInfo.userInfo?.router_list)
}
/** 跳轉(zhuǎn)到用戶路由列表中的第一個路由 */
router.replace(routerListArr[0].path)
}, (err) => {
/** 錯誤提示 */
ElMessage({
message: err.response.data.message,
type: 'error'
})
})
}
</script>pinia代碼
import {ref} from 'vue'
import {defineStore} from 'pinia'
import type {RouterListItem, UserInfo} from '@/types/login'
/** 導(dǎo)入的是自己的路由文件 src-router-index.ts */
import myRouter from '@/router/index'
/** 用戶信息相關(guān) */
export const useUserInfo = defineStore(
'userInfo',
() => {
/** 用戶信息 */
const userInfo = ref<UserInfo | undefined>(undefined)
/** 存儲用戶信息方法 */
const setUserInfo = (info: UserInfo): void => {
userInfo.value = info
}
/** 清除用戶信息方法-用于退出登錄或token驗證失敗 */
const clearUserInfo = (): void => {
userInfo.value = undefined
}
/** 注冊路由方法 */
const registeredRoute = () => {
/** 判斷userInfo.value是否為undefined,不是則進(jìn)入 */
if (userInfo.value !== undefined) {
/** 由于我的后端返回路由列表是JSON格式,需要轉(zhuǎn)換后使用 */
const routerListArr: RouterListItem[] = JSON.parse(userInfo.value?.router_list)
/** 通過循環(huán)添加路由 */
for (const item of routerListArr) {
const route = {
path: item.path,
name: item.name,
meta: {
navBar: item.meta.navBar,
token: item.meta.token
},
/** 懶加載導(dǎo)入vue頁面
由于我的后端返回的component名稱是帶有后綴名的,直接導(dǎo)入vite會報警告,雖然不影響使用,但是安全起見
還是替換了為好,這里使用replace將.vue替換為空
*/
component: () => import(`../views/${item.component.replace('.vue', '')}.vue`)
}
myRouter.addRoute(route)
}
}
}
return {
userInfo,
setUserInfo,
clearUserInfo,
registeredRoute
}
},
{
/** pinia持久化 */
persist: true
})
/** 用戶token相關(guān) */
export const useMyToken = defineStore(
'myToken',
() => {
/** token信息 */
const myToken = ref<string | undefined>(undefined)
/** 存儲token信息方法 */
const setMyToken = (token: string) => {
myToken.value = token
}
/** 清除token信息方法-用于退出登錄或token驗證失敗 */
const clearMyToken = () => {
myToken.value = undefined
}
return {
myToken,
setMyToken,
clearMyToken
}
},
{
/** pinia持久化 */
persist: true
})
關(guān)于替換.vue后綴的說明
導(dǎo)入必須以 或 開頭。./…/
所有導(dǎo)入都必須相對于導(dǎo)入文件開始。導(dǎo)入不應(yīng)以變量、絕對路徑或裸導(dǎo)入開頭:
// Not allowed
import(bar);
import(`${bar}.js`);
import(`/foo/${bar}.js`);
import(`some-library/${bar}.js`);導(dǎo)入必須以文件擴展名結(jié)尾
文件夾可能包含您不打算導(dǎo)入的文件。因此,我們要求導(dǎo)入在導(dǎo)入的靜態(tài)部分中以文件擴展名結(jié)尾。
// Not allowed
import(`./foo/${bar}`);
// allowed
import(`./foo/${bar}.js`);導(dǎo)入到您自己的目錄必須指定文件名模式
如果您導(dǎo)入自己的目錄,則最終可能會得到您不打算導(dǎo)入的文件,包括您自己的模塊。因此,需要提供更具體的文件名模式:
// not allowed
import(`./${foo}.js`);
// allowed
import(`./module-${foo}.js`);詳細(xì)信息見文檔:dynamic-import-vars#limitations
main代碼(vue的main.ts文件內(nèi))
import './assets/main.css'
import {createApp} from 'vue'
import App from './App.vue'
import router from './router'
/** 導(dǎo)入createPinia用于創(chuàng)建pinia */
import {createPinia} from 'pinia'
/** 導(dǎo)入ElementPlus */
import ElementPlus from 'element-plus'
/** 導(dǎo)入ElementPlus國際化文件-中文 */
import zhCn from 'element-plus/es/locale/lang/zh-cn'
/** 導(dǎo)入pinia持久化插件 */
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
/** 導(dǎo)入pinia內(nèi)的useUserInfo,用于動態(tài)注冊路由 */
import {useUserInfo} from '@/stores/counter'
/** 導(dǎo)入el-loading樣式 */
import 'element-plus/theme-chalk/el-loading.css'
/** 導(dǎo)入el-message樣式 */
import 'element-plus/theme-chalk/el-message.css'
import type {Pinia} from 'pinia'
const app = createApp(App)
/** 創(chuàng)建pinia */
const pinia: Pinia = createPinia()
/** 注冊piniaPluginPersistedstate持久化插件 */
pinia.use(piniaPluginPersistedstate)
/** 注冊pinia */
app.use(pinia)
/** 獲取pinia內(nèi)的userInfo,用于動態(tài)注冊路由 */
const userInfo = useUserInfo()
/** 動態(tài)注冊路由,并且防止刷新頁面導(dǎo)致路由丟失
這里直接調(diào)用userInfo.registeredRoute()會不生效,需要寫到函數(shù)內(nèi)部,再調(diào)用函數(shù)
并且需要寫在app.use(router)之前
*/
const addRouter = () => {
userInfo.registeredRoute()
}
addRouter()
app.use(router)
/** 注冊ElementPlus,并使用中文模式 */
app.use(ElementPlus, {
locale: zhCn,
})
app.mount('#app')總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue webpack build資源相對路徑的問題及解決方法
這篇文章主要介紹了vue webpack build資源相對路徑的問題,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06
vue-cli腳手架build目錄下utils.js工具配置文件詳解
這篇文章主要介紹了vue-cli腳手架build目錄下utils.js工具配置文件詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-09-09
利用vuex-persistedstate將vuex本地存儲實現(xiàn)
這篇文章主要介紹了利用vuex-persistedstate將vuex本地存儲的實現(xiàn),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-04-04
LRU算法在Vue內(nèi)置組件keep-alive中的使用
LRU算法全稱為least recently use 最近最少使用,核心思路是最近被訪問的以后被訪問的概率會變高,那么可以把之前沒被訪問的進(jìn)行刪除,維持一個穩(wěn)定的最大容量值,從而不會導(dǎo)致內(nèi)存溢出。2021-05-05
Vue3中使用pnpm搭建monorepo開發(fā)環(huán)境
這篇文章主要為大家介紹了Vue3中使用pnpm搭建monorepo開發(fā)環(huán)境示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08

