vue当中addRoutes动态添加路由白屏解决和next(),next(“/“)的一些区别
vue当中addRoutes动态添加路由白屏解决和next(),next("/")的一些区别
·
问题产生前言
-
使用动态添加路由
router.addRoutes()
后进入一个页面,对着这一个页面刷新一下,然后页面就白屏了并且不管刷新多少次都没有用,依旧是白屏,只有重新进入页面才有效果- 比如对于网站
http://localhost:9528/#/product/attr/list
,现在显示是正常的,对着这一个页面刷新一下,页面就白屏了,刷新多少次都没有用,必须要重新访问一次路由才可以必须要重新访问一次网站才可以(只要不再次刷新就可以)
- 比如对于网站
问题分析
-
动态添加路由无非就是几个过程
- router.addRoutes();
- 页面访问动态生成的路由
-
步骤1没有问题,问题就出现在页面访问动态生成的路由上面
我们再来分析下过程
- 页面被刷新,路由信息被重新计算生成并通过
addRoutes
方法动态添加到了router
当中 addRoutes
方法还没有完成,用户就已经在访问界面了(可以理解为addRoutes
和访问路由同时进行)- 用户一边访问界面,后面一边动态添加路由,
addRoutes
相当于还没有完成就被访问了路由(可以理解访问了一个此刻不存在的路由导致的白屏) - 所以必须要必须要重新访问一次路由才可以解决白屏问题
要怎么解决这个问题?
解决办法
-
不应该使用
next()
-
全局前置守卫使用
next({ ...to, replace: true })
-
next({ ...to});
也是可以的next({ ...to, replace: true })中的replace: true 只是一个设置信息,告诉VUE本次操作后,不能通过浏览器后退按钮,返回前一个路由 //换句话说,你使用了replace:true后重新访问了网站 //就不可以通过浏览器来返回页面之前和之后的网站了 举例子: //比如我刷新之前依次!依次!依次!访问了下面二个网站 网站1: http://localhost:9528/#/product/attr/list 网站2: http://localhost:9528/#/product/spu/list 那么按照平时的来说,我刷新页面依旧可以使用浏览器的前进后退按钮进行跳转了,后退按下,跳转到了网站1,然后此时前进按下,跳转到网站2 //但是如果使用了replace:true 那么刷新网页后就不可以通过前进后退按钮来后退了,之前记录都无效了
-
动态添加路由,全局前置守卫应该修改成为如下代码(只是示例参考)
- 下面代码是来自vue-element-admin模板当中src\permission.js文件夹的~这里进行了修改举例
//如果token存在
if (hasToken) {
//token存在了还访问登录界面,就跳转到首页去
if (to.path === '/login') {
next({path: '/'});
NProgress.done();
}
//token存在并且访问的不是登录地址
else {
//获取用户名
const hasGetUserInfo = store.getters.name;
//用户名存在
if (hasGetUserInfo) {
//放行
next()
}
//用户名不存在,说明token过期了或者被删除了
else {
try {
//发送请求获取并存储用户信息
await store.dispatch('user/getInfo')
//用于是动态添加的路由,所以这里应该修改
// next();
//改为这个
next({...to});
//或者
// next({...to,replace:true});
}
//发生错误
catch (error) {
//移除token信息(不移除这个全局前置守卫就是死循环!)
await store.dispatch('user/resetToken')
//弹出信息框
Message.error(error || 'Has Error')
//跳转到登录页面
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
}
}
//token不存在
else {
//如果用户访问的是登录界面,放行
if ('/login' == to.path) {
next()
}
//用户访问的不是登录界面,跳转到登录界面并携带跳转之前的网址
//这样子当用户登录成功后就可以跳转到用户之前想去的网址
else {
next(`/login?redirect=${to.path}`)
NProgress.done()
}
}
为什么next()换为next({…to})(或者next({…to,replace:true}))就可以了,next和这二个区别在哪里
首先我们需要知道路由守卫(全局前置守卫为例子)
-
先上代码
beforeEach((to, from, next) => { to // 要去的路由 from // 当前路由 next() // 放行的意思 }
-
代码很简单,但是除了
next()
我们应该还见过next("/")
next("/login")
next({...to})
next({...to,replace:true})
等 -
在路由守卫当中,只有
next()
是放行(放你通过,不会在审核),而next("/")
next("/login")
next({...to})
next({...to,replace:true}
等,都是中断当中的全局前置守卫,执行新的全局前置守卫-
中断当中的全局前置守卫,执行新的全局前置守卫意思就是会再次调用beforeEach
-
如下面代码例子
//比如这个,你一定以为是跳转到"/login"就完事了 beforeEach((to, from, next) => { next('/login') } //实际上执行的过程代码 beforeEach((to, from, next) => { beforeEach(('/logon', from, next) => { beforeEach(('/logon', from, next) => { beforeEach(('/logon', from, next) => { beforeEach... // 一直循环下去...... , 因为我们没有使用 next() 放行 } } } }
-
一直循环下去导致溢出
-
再来看看这里例子 地址栏输入/home(从哪里来的不重要,我们只需要关注到哪里去)
beforeEach((to, from, next) => { //如果目的地址等于 '/home' //就跳转到 登录地址 '/login' if(to.path === '/home') { next('/login') } // 如果要去的地方不是 /home ,就放行 else { next();//放行 } } //访问过程如下代码 beforeEach((to, from, next) => { //进行了中断跳转,会再次调用beforeEach去判断,此时的目的地址是'login'了 beforeEach(('/login', from, next) => { // 现在要去的地方不是 /home , 因此放行 next(); } }
看看这代码执行的流程图
-
总结
next()
是放行,不会引发beforeEach再次调用next("/")
next("/login")
next({...to})
next({...to,replace:true})
这些是中断(也就是会再次调用beforeEach),直到执行到了next()才会停止中断
大家可以看看这些全局前置守卫死循环的例子
这些都是死循环,使用就出现Maximum call stack size exceeded
死循环1
router.beforeEach((to, from, next) => {
console.log('beforeEach');
if (true) {
next('/');
} else {
next();
}
});
死循环2
router.beforeEach((to, from, next) => {
var user = JSON.parse(sessionStorage.getItem('user'));
if(user == null){
next({ path: '/login' }); // 没有用户,就跳去登录
} else {
next();
}
});
死循环3
router.beforeEach((to,from,next) =>{
if (sessionStorage.getItem("token")) {
if(to.path === "/login"){
next({path:"/dashboard"})
}
else{
alert("1")
next()
}
}else{
next({path: "/login"}) // 会再次执行前置导航守卫,由于路径变化
}
})
更多推荐
已为社区贡献7条内容
所有评论(0)