vue-router router.beforeEach浅析

准备知识

vue-router几个钩子函数,vue-router钩子函数官方解释

遇到问题

在用vue-element-admin做一个权限记录时,遇到了一个问题,问题描述:

   动态增加的用户权限时,在动态增加权限页面按下F5刷新的时候,会必现无法加载到正确的组件,直接跳转到/404页面

动态增加路由的代码如下:

```javascript

router.beforeEach(async (to, from, next) => {

// start progress bar

  NProgress.start()

// set page title

  document.title =getPageTitle(to.meta.title)

// determine whether the user has logged in

  const hasToken =getToken()

if (hasToken) {

if (to.path ==='/login') {

// if is logged in, redirect to the home page

      next({path:'/'})

NProgress.done()

}else {

const hasGetUserInfo = store.getters.name

      if (hasGetUserInfo) {

next()

}else {

try {

// get user info

          console.log(`to ----> `, to)

await store.dispatch('user/getInfo')

if (store.getters.roles.length !==0) {// 判断当前用户是否已拉取完user_info信息

            const roles = store.getters.roles

            const accessRoutes =await store.dispatch('GenerateRoutes', {roles})

router.addRoutes(accessRoutes)

next({...to, replace:true})

          }

        }catch (error) {

// remove token and go to login page to re-login

          await store.dispatch('user/resetToken')

Message.error(error ||'Has Error')

next(`/login?redirect=${to.path}`)

NProgress.done()

}

}

}

}else {

/* has no token*/

    if (whiteList.indexOf(to.path) !== -1) {

// in the free login whitelist, go directly

      next()

}else {

// other pages that do not have permission to access are redirected to the login page.

      next(`/login?redirect=${to.path}`)

NProgress.done()

}

}

})

```   

路由定义:

```javascript

export const constantRouterMap = [

{

path:'/login',

    component: () =>import('@/views/login/index'),

    hidden:true

  },

  {

path:'/register',

    component: () =>import('@/views/login/register'),

    hidden:true

  },

  {

path:'/edit_password',

    component: () =>import('@/views/login/editPassword'),

    hidden:true

  },

  {

path:'/404',

    component: () =>import('@/views/404'),

    hidden:true

  },

  {

path:'/',

    component: Layout,

    redirect:'/dashboard',

    children: [{

path:'dashboard',

      name:'首页',

      component: () =>import('@/views/dashboard/index'),

      meta: {title:'首页', icon:'home'}

}]

}

]

},

]

},

  // 404 page must be placed at the end !!!

  {path:'*', redirect:'/404', hidden:true}

]

export const asyncRouterMap = [

  {

path:'/configuration_page',

    component: Layout,

    children: [

{

path:'/conf_page',

        name:'ConfPage',

        component: ConfPage,

        meta: {title:'配置页面', icon:'conf_page', role: ['sysadmin']}

}

]

}

]

const createRouter = () =>new Router({

// mode: 'history', // require service support

  scrollBehavior: () => ({y:0}),

  routes: constantRouterMap

})

const router =createRouter()

// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465

export function resetRouter () {

const newRouter =createRouter()

router.matcher = newRouter.matcher // reset router

}

export default router

```   

定位问题

1.刷新时在router.beforeEach加了打印回调to的值,发现to此时已经变为/404,所以问题应该不是出现在动态增加路由的地方

2.查看了router官方文档,

完整的导航解析流程导航被触发。

1.在失活的组件里调用离开守卫。

2.调用全局的 beforeEach 守卫。

3.在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。

4.在路由配置里调用 beforeEnter。

5.解析异步路由组件。

6.在被激活的组件里调用 beforeRouteEnter。调用全局的 beforeResolve 守卫 (2.5+)。导航被确认。调用全局的 afterEach 钩子。触发 DOM 更新。

7.用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数

官网并没有指明vue是什么时候去匹配路由的,继续网上查找资料,终于在查到了这句话

理论上应该是这样的,但问题是next 方法不是异步的,每当触发router 的勾子时,实际上目标的 route 已经获取完成了,不会再去重新获取,导致即使进行了 commit,也不会去取最新的。可以参考下源码:https://github.com/vuejs/vue-router/blob/d539788df8394efe41c1534e1e9d1555aa2edbe2/src/history/base.js#L163 248这个 route 在执行 next 的时候是不会产生变化的,在第一次导航时候应该就已经确定了。

通过这段话基本确认了在进入beforeEach之前,vue就已经根据静态配置的路由匹配到了/404,这个段话还可以对比vue的源码继续深入研究一下,刷新的具体过程,后续继续学习。

综上的分析:为了让正确的匹配,把/404这个path的匹配到的path放到动态的路由里面,使path不能在静态路由里面匹配,直到动态路由匹配,问题解决。修改代码如下:

```javascript

export const constantRouterMap = [

{

path:'/login',

    component: () =>import('@/views/login/index'),

    hidden:true

  },

  {

path:'/register',

    component: () =>import('@/views/login/register'),

    hidden:true

  },

  {

path:'/edit_password',

    component: () =>import('@/views/login/editPassword'),

    hidden:true

  },

  {

path:'/404',

    component: () =>import('@/views/404'),

    hidden:true

  },

  {

path:'/',

    component: Layout,

    redirect:'/dashboard',

    children: [{

path:'dashboard',

      name:'首页',

      component: () =>import('@/views/dashboard/index'),

      meta: {title:'首页', icon:'home'}

}]

}

]

},

]

}

]

export const asyncRouterMap = [

  {

path:'/configuration_page',

    component: Layout,

    children: [

{

path:'/conf_page',

        name:'ConfPage',

        component: ConfPage,

        meta: {title:'配置页面', icon:'conf_page', role: ['sysadmin']}

}

]

},

// 404 page must be placed at the end !!!

  {path:'*', redirect:'/404', hidden:true}

]

const createRouter = () =>new Router({

// mode: 'history', // require service support

  scrollBehavior: () => ({y:0}),

  routes: constantRouterMap

})

const router =createRouter()

// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465

export function resetRouter () {

const newRouter =createRouter()

router.matcher = newRouter.matcher // reset router

}

export default router

```  

特别说明

router.addRoutes(accessRoutes)并不会改变router.options.routes的值,router.options.routes在初始化就已经确定了的,

那addRoutes的实现原理待深入分析

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容