若依Vue2.0框架学习之路由跳转
免责声明
- 新项目在若依前后端分离(Vue2.6.x + Springboot2.2.x)模板基础上进行项目开发,苯人真得学学模板吧!理解错误概不负责,毕竟ko no 菜鸡一枚 da。
- 我们幼儿园有适合自己看的注释拉满文档!
- 本篇只涉及路由跳转,什么登录流程和权限管理先往后稍稍。
0. next()
前情提要:假设当前导航是从 A 到 B,新的导航是从 A 到 C。
0.1 next()
放行,允许从 A 到 B。
0.2 next(false)
不仅中断当前导航,也没有新的导航。
0.3 next('/xxx') 或 next({ path:'/xxx',... })
中断当前导航,执行新的导航;即又会进入一次前置守卫。
0.4 next(error) 2.4.0+
如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。(船新的api)
1. Vue.config.js 项目启动
const port = process.env.port || process.env.npm_config_port || 80 // 端口
// 省略版
module.exports = {
// ...
devServer: {
host: '0.0.0.0',
port: port,
// ...
}
}
项目启动 http://localhost:80/
2. 路由跳转
2.1 router/index.js 路由配置
关注根路径的重定向
// ==== 省略版 ====
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
/* Layout */
import Layout from '@/layout'
// 公共路由
export const constantRoutes = [
{
path: '/redirect',
component: Layout,
hidden: true,
children: [
{
path: '/redirect/:path(.*)',
component: () => import('@/views/redirect')
}
]
},
{
path: '/login',
component: () => import('@/views/login'),
hidden: true
},
{
path: '/404',
component: () => import('@/views/error/404'),
hidden: true
},
// ''也可以匹配上'/'的
{
path: '',
component: Layout,
// 重定向到子路由
redirect: 'index',
children: [
{
path: 'index',
component: () => import('@/views/index'),
name: 'Index',
meta: { title: '首页', icon: 'dashboard', affix: true }
}
]
},
]
export default new Router({
mode: 'history', // 去掉url中的#
routes: constantRoutes
})
2.2 路由前置守卫
2.2.1 未登录(cookie 中无 token),直接访问非白名单内某配置了的页面,会跳转到 login 页
permission.js
关注 1. 跳转到了login页 2. fullPath为 /login?redirect=/xxx
import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { getToken } from '@/utils/auth'
import { isRelogin } from '@/utils/request'
NProgress.configure({ showSpinner: false })
// 只关心路由前置守卫以及路由跳转捏
const whiteList = ['/login', '/register']
// 0. 项目启动 http://localhost:80/ 在router.js 中配置了,重定向到子路由 index,导航是从 / 到 /index
router.beforeEach((to, from, next) => {
NProgress.start()
if (getToken()) {
// 略
} else {
// a 1. 没有token 3. 没有token
if (whiteList.indexOf(to.path) !== -1) {
// a 4. to.path == /login 在白名单
// a 5. next() 跳转到 login 页,fullPath 为 /login?redirect=/index 至此 finished
next()
} else {
// 2. 此时 to 路由对象的 path 是 /index 不在白名单
next(`/login?redirect=${to.fullPath}`) // 否则全部跳转到登录页,且此处参数redirect是为了后面点击登录验证成功后直接跳转到本来想访问的页面
// 新的 to 路由对象的 fullPath 为 /login?redirect=/index
NProgress.done()
}
}
})
router.afterEach(() => {
NProgress.done()
})
2.2.2 接上续,点击登录通过验证,跳转到原目标页,这里以 index 举例
views/login.vue
<script>
name: "Login",
data() {
return {
// ...
redirect: undefined
};
},
watch: {
// 经过重定向 + 守卫,此时的 $route: { path:"/login",query: {redirect: "/index"},fullpath: "/login?redirect=%2Findex",...}
$route: {
handler: function(route) {
this.redirect = route.query && route.query.redirect;
},
immediate: true
}
},
handleLogin() {
this.$refs.loginForm.validate(valid => {
if (valid) {
// ...
this.$store.dispatch("Login", this.loginForm).then(() => {
// 暂时只关注这一行,点击登录按钮,验证成功后,跳转到 index.vue to : { path : /index }
this.$router.push({ path: this.redirect || "/" }).catch(()=>{});
}).catch(() => {
this.loading = false;
if (this.captchaEnabled) {
this.getCode();
}
});
}
});
}
</script>
permission.js
import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { getToken } from '@/utils/auth'
import { isRelogin } from '@/utils/request'
NProgress.configure({ showSpinner: false })
// 只关心路由前置守卫捏
const whiteList = ['/login', '/register']
// 0. 接上文,此时 to : {path : /index}
router.beforeEach((to, from, next) => {
NProgress.start()
if (getToken()) {
// b 1. 有token 4. 有token
to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
if (to.path === '/login') {
next({ path: '/' })
NProgress.done()
} else {
// 判断当前用户是否已拉取完 user_info 信息(因为即使没有也会赋一个默认的,所以只要是 0 肯定没拉)
// b 2. 没拉取完,先发送请求获取(这里涉及 vuex 和权限,不展开)
if (store.getters.roles.length === 0) {
isRelogin.show = true
store.dispatch('GetInfo').then(() => {
isRelogin.show = false
store.dispatch('GenerateRoutes').then(accessRoutes => {
router.addRoutes(accessRoutes)
// b 3. fulfilled
// 此时新的路由为 { path: '/index',replace :true} 这里的 replace属性使得当前的push方法变成像this.$router.replace一样 不会向 history 添加新纪录
next({ ...to, replace: true })
})
}).catch(err => {
// rejected
store.dispatch('LogOut').then(() => {
Message.error(err)
// 登出后,此时 cookie 里的 token 已清除;因此同2.2.1
// 但是这里为什么不直接写 next({ path: '/login' }) ???
next({ path: '/' })
})
})
// b 5. 拉取完,直接放行 { path: '/index',replace :true } 跳转到原目标页
} else {
next()
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
next(`/login?redirect=${to.fullPath}`)
NProgress.done()
}
}
})
router.afterEach(() => {
NProgress.done()
})
2.2.3 已登录(cookie 中有 token),再访问 login 页,会重定向到 index 页
import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { getToken } from '@/utils/auth'
import { isRelogin } from '@/utils/request'
NProgress.configure({ showSpinner: false })
const whiteList = ['/login', '/register']
router.beforeEach((to, from, next) => {
NProgress.start()
if (getToken()) {
// c 有 token 再访问 login 页 1. has token 3. has token 6. has token
to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
if (to.path === '/login') {
// c 2. 访问 login 页 匹配上''会重定向,直接改变了to,因此5.的path是 /index
next({ path: '/' })
NProgress.done()
} else {
// 判断当前用户是否已拉取完 user_info 信息(因为即使没有也会赋一个默认的,所以只要是0肯定没拉,好吧这里也涉及权限,暂时不用管)
// c 4. 因为直接改变url模拟 肯定会刷新页面,因此走没拉取完
// 注: user_info 存在 vuex 里,vue本质是单页面, 路由的跳转不会刷新页面,但重新输入url会
if (store.getters.roles.length === 0) {
isRelogin.show = true
store.dispatch('GetInfo').then(() => {
isRelogin.show = false
store.dispatch('GenerateRoutes').then(accessRoutes => {
router.addRoutes(accessRoutes)
// c 5. to: { path: '/index' }
next({ ...to, replace: true })
})
}).catch(err => {
store.dispatch('LogOut').then(() => {
Message.error(err)
next({ path: '/' })
})
})
} else {
// 7. 拉取完了 { path: '/index', replace: true } 放行
next()
}
}
} else {
if (whiteList.indexOf(to.path) !== -1) {
next()
} else {
next(`/login?redirect=${to.fullPath}`)
NProgress.done()
}
}
})
router.afterEach(() => {
NProgress.done()
})