vue-admin-template动态添加路由,刷新页面路由失效问题

基本思路

1.请求后端接口,返回一个菜单数组的json格式数据。

2.前端拿到返回值之后将菜单数组中需要的数据进行组装成一个路由认识的json对象数组。

3.路由中某个方法可以设置进行并渲染。

4.以上工作都准备好之后,想一下放在哪里比较合适。

实现

思路1

后端创建菜单数据,我采用的基本json格式如下

{
    data:[{
        path:'',//路径 根菜单要加/
        component:'',//组件路径,如果没有组件名称又是根菜单 && 没有children 则使用Layout
        name:'',//菜单名称
        hidden:true,//是否隐藏菜单
        alwaysShow:true,//是否展开
        icon:'图标',//菜单图标
        children:[]//子菜单
	}]
}

思路2

将后端返回的数据进行解析并加工,这里非常关键。因为涉及到动态解析组件,我这里是创建了一个menu-util.js文件把方法都写在这里面然后暴露,大家可以借鉴参考。

import Layout from '@/layout'

/**
 * 刷新菜单
 * @param menus
 * @param router
 * @param store
 */
export function refreshMenus(menus,router,store) {
   //调用处理菜单方法
  const remoteRoutes=handleMenu(menus)
  //添加到路由规则
  router.addRoutes(remoteRoutes)
  //添加到路由中
  router.options.routes=router.options.routes.concat(remoteRoutes)
  //在vuex中存储一个变量 refreshPage
  store.dispatch('app/setRefreshPage');
}

//处理菜单
export function handleMenu(menus){
  menus=menus.map(item=>{
      if(item.component){
        let path = item.component;
        // item.component = ()=>import(`@/views/${path}.vue`) //不能这么写,webpack4不支持
        item.component = resolve=>require([`@/views/${path}`],resolve)
      }else{
        item.component=Layout
      }
      item.meta = {title:item.name,icon:item.icon}
      if(item.children && item.children.length>0){
        item.children=handleMenu(item.children)
      }
      return item;
  })
  return menus;
}

这里写了一个刷新菜单方法refreshMenus和 处理菜单方法handleMenu

handleMenu:将后端接收的菜单数据进行加工的地方

refreshMenus:刷新菜单方法是封装的步骤方法,因为代码中多处地方要用到,所以统一了一下。

思路3

思路2中的刷新菜单handleMenu方法中的第2,3行代码体现。

this.$router.addRoutes();//往路由规则中添加后端传递
this.$store.options.routes.concat()//添加路由

思路4

上面的操作完成后基本所有的准备工作都完成就绪,就差一步,思考应该放在哪里比较合适。楼主是放在了2个地方,登录全局守卫

登录位置

在你自己代码的登录部分,当登录成功后,后端应该要返回当前用户的菜单数据用于里面的菜单渲染。

import {refreshMenus} from '@/utils/menu-util';
//处理登录
handleLogin() {
      this.$refs.loginForm.validate(valid => {
        if (valid) {
          this.loading = true
          this.$store.dispatch('user/login', this.loginForm).then((response) => {
            let { data:{menus} } = response;
            // 刷新菜单方法构造真正的路由配置
            refreshMenus(menus,this.$router,this.$store)
            this.$router.push({ path: this.redirect || '/' })
            this.loading = false
         }).catch(() => {
            this.loading = false
          })
        } else {
          console.log('error submit!!')
          return false
        }
      })
    }

其实到这里你就能看到你想要的效果了,但是真正的问题才开始展现,这里就是为什么我还要在全局守卫这也要加这种代码。

全局守卫位置

查看vue-admin-template后台模板中,route的beforeEach方法在permission.js中。我上面为什么说有重大问题,还在兴高采烈的小伙伴这时候可以尝试刷新一下你当前页面,惊喜天上来。

是不是菜单没了!这是因为刷新页面,VueX的数据会丢失,router会被重新创建。那咋搞?楼主是这么想的,既然刷新页面之后VueX里面的值会变,那我就在VueX的store中存储一个值,然后登录的时候设置成其他值,如果页面刷新肯定会把值恢复,这样我就可以根据这个字段来判断是否是刷新页面了。这就是思路2中的refreshMenus方法中最后一行代码的由来.

//在vuex中存储一个变量 refreshPage,将refreshPage设置成false
  store.dispatch('app/setRefreshPage');

在这里插入图片描述

将refreshPage默认设置成true,refreshMenus方法中会将该属性变成false,别说看不懂这个代码,看不懂的得去稍微看一下VueX,楼主比你们还菜,js会的也是只有一点点

关键的代码来了,就是在router.beforeEach方法中如何解决刷新页面路由重置问题。

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 {
       //=====关键看这里 ---start============ 
      // 判断如果刷新了页面 则获取后台菜单
      if(store.state.app.refreshPage){
         getMenus().then(response=>{
            refreshMenus(response.data,router,store)
          })
      }
        //=====关键看这里 ---end=============== 
      const hasGetUserInfo = store.getters.name
      if (hasGetUserInfo) {
        next()
      } else {
        try {
          // get user info
          await store.dispatch('user/getInfo')
          next()
        } 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()
    }
  }

})

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>