??? vue动态路由(约定路由),听起来好像很玄乎的样子? 但是你要是理解了实现思路,你会发现,没有想象中的那么难?
在没有亲自实现功能前,永远不要低估自己的个人实力和潜力???
???下面是本人一个刚从服务端开发转职前端开发的程序猿的实现过程???
实现思路
思路其实很简单,也很明确:
1、将路由分为静态路由(staticRouters)、动态路由
2、静态路由初始化时正常加载
3、用户登陆后,获取相关动态路由数据,
4、然后利用vue:addRoute追加到vue实例中即可。 实现思路虽然很简单,但是过程并不是一帆风顺,需要注意的细节还是很多的
环境介绍
- vue-cli: v4.x.x
- vue: v2.6.11
- vuex: v3.4.0
- vue-router: v3.2.0
实现过程
路由文件处理(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'),
},
]
},
]
// 定义静态路由集合
const staticRouterMap = [
'home',
'lists',
'detail'
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
})
// 路由全局拦截
// 以下可根据业务逻辑自行在拦截路由中进行处理,此处仅以本人业务作为示例展示
// 本示例以 vuex+sessionStorage相互配合完成动态路由的数据存储
// 仅以vuex存储获取到的动态路由信息后,在刷新页面时,动态路由信息是会丢失,
// 从而导致页面404
router.beforeEach((to, from, next) => {
const userState = JSON.parse(sessionStorage.getItem('userState'))
if (!userState || !userState.isLogin) {
// 没有登录
// 如果前往页面非公共路由,则跳转至首页
if (staticRouterMap.indexOf(to.name) < 0) {
next({name: 'home'})
} else {
next()
}
} else {
// 登录
// 已经存在路由列表: 注意刚登陆成功第一次调转route时相应store数据还未更新
const hasGetRoute = store.getters['user/hasGetRoute']
const routeMap = JSON.parse(sessionStorage.getItem('routeMap'))
if(!hasGetRoute && routeMap) {
// 刷新页面且有route记录数据,可再次追加动态路由
store.dispatch('user/updateRouteOfUser', routeMap)
next({...to, replace: true})
} else {
next()
}
}
})
export default router
view数据处理
<template>
<div class="home">
<div>
这是demo
</div>
<div>
<div v-show="!isLogin">
<a-divider>调用接口: 模拟登陆</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()
//以下就是根据用户登陆信息,获取动态路由信息操作
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: {
// 用户状态相关
userState: JSON.parse(sessionStorage.getItem('userState')) || {ut: '', isLogin: false, userType: null},
// 用户信息相关
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
// 为了防止用户刷新页面导致动态创建的路由失效,将其存储在本地中
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)
})
},
// 获取用户授权动态路由
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) => {
// 区分布局与视图文件,因为加载方式不同
if (router.component === 'Layout') {
router.component = Layout
}else {
// view
router.component = loadView(router.component)
}
// 删除路由记录中的无用字段:这段是本示例与后台协商的,但在vue-router中不被支持的字段信息,可忽略
if (!router.redirect || !router.redirect.length) { delete router.redirect }
// 判断是否存在子路由,并递归调用自己
if(router.children && router.children.length) {
router.children = filterRouter(router.children)
}
return true
})
}
// mock 数据
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;
路由数据(demo)
贡献本人于服务端约定的路由数据结构,仅供参考
{
"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": {}
}
]
},
]
}
]
}
到此这篇关于Vue router动态路由实现过程的文章就介绍到这了,更多相关Vue router动态路由内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!