Vue router動態(tài)路由實現(xiàn)過程
?????? vue動態(tài)路由(約定路由),聽起來好像很玄乎的樣子?? 但是你要是理解了實現(xiàn)思路,你會發(fā)現(xiàn),沒有想象中的那么難??
在沒有親自實現(xiàn)功能前,永遠不要低估自己的個人實力和潛力??????
??????下面是本人一個剛從服務端開發(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è)務邏輯自行在攔截路由中進行處理,此處僅以本人業(yè)務作為示例展示 // 本示例以 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時相應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)
貢獻本人于服務端約定的路由數(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-08vue中對監(jiān)聽esc事件和退出全屏問題的解決方案
這篇文章主要介紹了vue中對監(jiān)聽esc事件和退出全屏問題的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08vue清除瀏覽器全部cookie的問題及解決方法(絕對有效!)
最近項目要實現(xiàn)關(guān)閉瀏覽器清除用戶緩存的功能,下面這篇文章主要給大家介紹了關(guān)于vue清除瀏覽器全部cookie的問題及解決方法,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-06-06vue中使用sass及解決sass-loader版本過高導致的編譯錯誤問題
這篇文章主要介紹了vue中使用sass及解決sass-loader版本過高導致的編譯錯誤問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-04-04Element-ui中元素滾動時el-option超出元素區(qū)域的問題
這篇文章主要介紹了Element-ui中元素滾動時el-option超出元素區(qū)域的問題,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-05-05