IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> vue-admin-template动态添加路由刷新页面路由失效问题 -> 正文阅读

[JavaScript知识库]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()
    }
  }

})
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-12-11 15:37:53  更:2021-12-11 15:39:02 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:29:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码