Vue router動態(tài)路由實現(xiàn)過程
?????? vue動態(tài)路由(約定路由),聽起來好像很玄乎的樣子?? 但是你要是理解了實現(xiàn)思路,你會發(fā)現(xiàn),沒有想象中的那么難??
在沒有親自實現(xiàn)功能前,永遠不要低估自己的個人實力和潛力??????
??????下面是本人一個剛從服務(wù)端開發(fā)轉(zhuǎn)職前端開發(fā)的程序猿的實現(xiàn)過程??????
實現(xiàn)思路
思路其實很簡單,也很明確:
1、將路由分為靜態(tài)路由(staticRouters)、動態(tài)路由
2、靜態(tài)路由初始化時正常加載
3、用戶登陸后,獲取相關(guān)動態(tài)路由數(shù)據(jù),
4、然后利用vue:addRoute追加到vue實例中即可。 實現(xiàn)思路雖然很簡單,但是過程并不是一帆風順,需要注意的細節(jié)還是很多的
環(huán)境介紹
- vue-cli: v4.x.x
- vue: v2.6.11
- vuex: v3.4.0
- vue-router: v3.2.0
實現(xiàn)過程
路由文件處理(router/index.js):
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeLayout from '../layouts/HomeLayout'
import store from '@/store/index'
Vue.use(VueRouter)
// 解決重復點擊路由報錯的BUG
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch((err) => err)
}
const routes = [
{
path: '/',
name: 'homeBase',
component: HomeLayout,
redirect: {
name: 'home'
},
children: [
// 門戶路由
{
path: 'home',
name: 'home',
component: () => import('../views/portal/Home.vue'),
},
{
path: 'lists',
name: 'lists',
component: () => import('../views/portal/Lists.vue'),
},
{
path: 'detail',
name: 'detail',
component: () => import('../views/portal/Detail.vue'),
},
]
},
]
// 定義靜態(tài)路由集合
const staticRouterMap = [
'home',
'lists',
'detail'
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
})
// 路由全局攔截
// 以下可根據(jù)業(yè)務(wù)邏輯自行在攔截路由中進行處理,此處僅以本人業(yè)務(wù)作為示例展示
// 本示例以 vuex+sessionStorage相互配合完成動態(tài)路由的數(shù)據(jù)存儲
// 僅以vuex存儲獲取到的動態(tài)路由信息后,在刷新頁面時,動態(tài)路由信息是會丟失,
// 從而導致頁面404
router.beforeEach((to, from, next) => {
const userState = JSON.parse(sessionStorage.getItem('userState'))
if (!userState || !userState.isLogin) {
// 沒有登錄
// 如果前往頁面非公共路由,則跳轉(zhuǎn)至首頁
if (staticRouterMap.indexOf(to.name) < 0) {
next({name: 'home'})
} else {
next()
}
} else {
// 登錄
// 已經(jīng)存在路由列表: 注意剛登陸成功第一次調(diào)轉(zhuǎn)route時相應(yīng)store數(shù)據(jù)還未更新
const hasGetRoute = store.getters['user/hasGetRoute']
const routeMap = JSON.parse(sessionStorage.getItem('routeMap'))
if(!hasGetRoute && routeMap) {
// 刷新頁面且有route記錄數(shù)據(jù),可再次追加動態(tài)路由
store.dispatch('user/updateRouteOfUser', routeMap)
next({...to, replace: true})
} else {
next()
}
}
})
export default router
view數(shù)據(jù)處理
<template>
<div class="home">
<div>
這是demo
</div>
<div>
<div v-show="!isLogin">
<a-divider>調(diào)用接口: 模擬登陸</a-divider>
<div style="margin-top:5px;">
<a-space :size="size">
<a-button type="primary" @click="login()">
用戶登陸
</a-button>
</a-space>
<p>{{loading}}</p>
</div>
</div>
</div>
</div>
</template>
<script>
// @ is an alias to /src
import {
Base64
} from 'js-base64'
import User from '../../api/user'
import {
mapGetters,
mapMutations,
mapActions
} from 'vuex'
export default {
name: 'home',
data() {
return {
size: "middle",
user: {
'name': 'xxxx',
'pass': Base64.encode('xxxx')
},
}
},
components: {},
computed: {
...mapGetters('user', ['isLogin', 'userInfo', 'hasGetRoute'])
},
methods: {
...mapMutations('user', ['setUserState']),
...mapActions('user', ['getUserInfo', 'getDynamicRouteOfUser']),
login() {
if (this.isLogin) {
this.$router.push({
path: '/user'
})
} else {
// 模擬用戶
User.login(this.user).then(res => {
this.setUserState({
'isLogin': true,
'ut': res.data.user_token,
'userType': 1
})
this.getUserInfo()
//以下就是根據(jù)用戶登陸信息,獲取動態(tài)路由信息操作
this.getDynamicRouteOfUser(type).then(() => {
this.$router.push({
path: '/user'
})
})
}).catch(() => {
})
}
},
},
}
</script>
<style lang="scss" scoped>
.home {
padding: 20px;
}
</style>vuex
import VueRouter from '../../router'
import UserApi from '../../api/user'
import axios from 'axios'
import TeacherLayout from '@/layouts/Layout'
import NotFound from '@/layouts/404'
const user = {
namespaced: true,
state: {
// 用戶狀態(tài)相關(guān)
userState: JSON.parse(sessionStorage.getItem('userState')) || {ut: '', isLogin: false, userType: null},
// 用戶信息相關(guān)
userInfo: JSON.parse(sessionStorage.getItem('userInfo')) || {},
// 是否獲取route
hasGetRoute: false,
// routeMap
routeMap: JSON.parse(sessionStorage.getItem('routeMap')) || [],
},
getters: {
ut : state => state.userState.ut,
isLogin: state => !!state.userState.isLogin,
userInfo: state => state.userInfo,
hasGetRoute: state => state.hasGetRoute,
routeMap: state => state.routeMap[0].children,
},
mutations: {
setUserState(state, playload) {
state.userState = playload
sessionStorage.setItem('userState', JSON.stringify(state.userState))
},
setUserInfo(state, playload) {
state.userInfo = playload
sessionStorage.setItem('userInfo', JSON.stringify(state.userInfo))
},
setRouteMap(state, routers) {
state.routeMap = routers
// 為了防止用戶刷新頁面導致動態(tài)創(chuàng)建的路由失效,將其存儲在本地中
sessionStorage.setItem('routeMap', JSON.stringify(routers));
},
setDynamicRouteMap(state, routers) {
state.hasGetRoute = true
let routerMaps = filterRouter(routers)
// 最后追加404路由
routerMaps.push({
path: '*',
component: NotFound
})
// 追加路由
// 這塊是重點,如果直接使用addRoute是無效的
routerMaps.forEach(item => {
VueRouter.addRoute(item);
})
},
resetLogin() {
sessionStorage.clear()
}
},
actions: {
// 獲取用戶信息
async getUserInfo({commit}) {
await UserApi.user().then(res => {
commit('setUserInfo', res)
}).catch(error => {
console.log(error)
})
},
// 獲取用戶授權(quán)動態(tài)路由
async getDynamicRouteOfUser({commit}, type) {
let flag = false
// mock api
mockRouter().then(res => {
commit('setRouteMap', res.data)
commit('setDynamicRouteMap', res.data)
flag = true
}).catch(err => {
console.log(err)
})
return flag
},
// 刷新重置路由
updateRouteOfUser({commit}, routerMap) {
commit('setDynamicRouteMap', routerMap)
},
}
}
// handle views
const loadView = (viewPath) => {
return () => import('@/views/' + viewPath)
}
// Handle routers
const filterRouter = (routers) => {
return routers.filter((router) => {
// 區(qū)分布局與視圖文件,因為加載方式不同
if (router.component === 'Layout') {
router.component = Layout
}else {
// view
router.component = loadView(router.component)
}
// 刪除路由記錄中的無用字段:這段是本示例與后臺協(xié)商的,但在vue-router中不被支持的字段信息,可忽略
if (!router.redirect || !router.redirect.length) { delete router.redirect }
// 判斷是否存在子路由,并遞歸調(diào)用自己
if(router.children && router.children.length) {
router.children = filterRouter(router.children)
}
return true
})
}
// mock 數(shù)據(jù)
async function mockRouter() {
const url = 'http://localhost:8080/t.json'
let routerData
await axios.get(url).then(res => {
routerData = res.data
}).catch(err => {
console.log(err)
})
return routerData
}
export default user;路由數(shù)據(jù)(demo)
貢獻本人于服務(wù)端約定的路由數(shù)據(jù)結(jié)構(gòu),僅供參考
{
"data":[
{
"title":"demo",
"name":"x",
"pname":"",
"path": "/x",
"type": 1,
"component": "Layout",
"redirect": {"name": "xx"},
"children": [
{
"title":"child1",
"name":"xx",
"pname":"x",
"path": "",
"type": 2,
"icon": "desktop",
"component": "xx.vue",
"redirect": {}
},
{
"title":"child1",
"name":"xx",
"pname":"tBase",
"path": "xx",
"type": 2,
"icon": "container",
"component": "xx.vue",
"redirect": {"name": "xxx"},
"children": [
{
"title":"child2",
"name":"xx",
"pname":"xx",
"path": "xx",
"type": 2,
"icon": "unordered-list",
"component": "xx.vue",
"redirect": {}
}
]
},
]
}
]
}
到此這篇關(guān)于Vue router動態(tài)路由實現(xiàn)過程的文章就介紹到這了,更多相關(guān)Vue router動態(tài)路由內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vue?axios和vue-axios的關(guān)系及使用區(qū)別
axios是基于promise的HTTP庫,可以使用在瀏覽器和node.js中,它不是vue的第三方插件,vue-axios是axios集成到Vue.js的小包裝器,可以像插件一樣安裝使用:Vue.use(VueAxios, axios),本文給大家介紹Vue?axios和vue-axios關(guān)系,感興趣的朋友一起看看吧2022-08-08
vue中對監(jiān)聽esc事件和退出全屏問題的解決方案
這篇文章主要介紹了vue中對監(jiān)聽esc事件和退出全屏問題的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08
vue清除瀏覽器全部cookie的問題及解決方法(絕對有效!)
最近項目要實現(xiàn)關(guān)閉瀏覽器清除用戶緩存的功能,下面這篇文章主要給大家介紹了關(guān)于vue清除瀏覽器全部cookie的問題及解決方法,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-06-06
vue中使用sass及解決sass-loader版本過高導致的編譯錯誤問題
這篇文章主要介紹了vue中使用sass及解決sass-loader版本過高導致的編譯錯誤問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-04-04
Element-ui中元素滾動時el-option超出元素區(qū)域的問題
這篇文章主要介紹了Element-ui中元素滾動時el-option超出元素區(qū)域的問題,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05

