精华内容
下载资源
问答
  • 第一步:src/router/index.js 公共路由定义 import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) /* Layout */ import Layout from '@/layout' export const constantRoutes = [{ path: '/...

    第一步:src/router/index.js 公共路由定义

    import Vue from 'vue'
    import Router from 'vue-router'
    Vue.use(Router)
    /* Layout */
    import Layout from '@/layout'
    export const constantRoutes = [{
            path: '/login',
            component: () =>
                import ('@/views/login/index'),
            hidden: true
        },
        {
            path: '/',
            hidden: true,
            component: Layout,
            redirect: '/dashboard',
            meta: { role: '/menu' },
            children: [{
                path: 'dashboard',
                name: '首页',
                component: () =>
                    import ('@/views/dashboard/index'),
                meta: { title: '首页', icon: 'dashboard', role: '/menu', affix: true }
            }]
        },
        {
          path: '/404',
          component: () =>
              import ('@/views/404'),
          hidden: true
        },
    ]
    const createRouter = () => new Router({
        // mode: 'history', // require service support
        scrollBehavior: () => ({ y: 0 }),
        routes: constantRoutes
    })
    const router = createRouter()
    export function resetRouter() {
        const newRouter = createRouter()
        router.matcher = newRouter.matcher // reset router
    }
    export default router
    
    

    第二步:src/store/modules/permission.js
    获取动态路由、和构造。

    import { constantRoutes } from '@/router'
    import store from '@/store'
    import { getRouter } from '@/api/user' // 获取路由的接口方法
    import Layout from '@/layout'
    import { MessageBox, Message } from 'element-ui'
    
    function hasPermission(roles, route) {
      if (route.meta && route.meta.roles) {
        return roles.some(role => route.meta.roles.includes(role))
      } else {
        return true
      }
    }
    const mutations = {
      SET_ROUTES: (state, routes) => {
        state.addRoutes = routes
        state.routes = constantRoutes.concat(routes) //动态路由与和镜态公共路由结合
        // console.log('state.routes',state.routes)
      }
    }
    /**
     * 把后台返回菜单组装成routes要求的格式
     * @param {*} routes
     */
    export function getAsyncRoutes(routes) {
      const res = []
      const keys = ['path', 'name', 'children', 'redirect','meta', 'hidden']
      routes.forEach(item => {
        const newItem = {}
        if (item.component) {
          if (item.component === 'Layout') {
            newItem.component = Layout
          } else {
            newItem.component = loadView(item.component);
          }
        }
        for (const key in item) {
          if (keys.includes(key)) {
            newItem[key] = item[key]
          }
        }
        if (newItem.children && newItem.children.length) {
          newItem.children = getAsyncRoutes(item.children)
        }
        res.push(newItem)
      })
      return res
    }
    export const loadView = (view) => {
      return (resolve) => require([`@/views${view}`], resolve)
    }
    export function filterAsyncRoutes(routes, roles) {
      const res = []
      routes.forEach(route => {
        const tmp = { ...route }
        if (hasPermission(roles, tmp)) {
          if (tmp.children) {
            tmp.children = filterAsyncRoutes(tmp.children, roles)
          }
          res.push(tmp)
        }
      })
      return res
    }
    const state = {
      routes: [],
      addRoutes: []
    }
    const actions = {
      generateRoutes({ commit }, roles) {
        return new Promise(async resolve => {
          let accessedRoutes
          // 请求接口 获取动态路由
          const routes = await getRouter() // 获取到动态路由接口
          if(routes.code == 200){
            if(routes.data.length > 0){
              const asyncRoutes = getAsyncRoutes(routes.data) // 对路由格式进行处理
              accessedRoutes = asyncRoutes
              commit('SET_ROUTES', asyncRoutes)
              resolve(accessedRoutes)
            }else{
              MessageBox.confirm('暂无菜单', '暂无菜单', {
                  confirmButtonText: '重新登录',
                  cancelButtonText: '取消',
                  type: 'warning'
              }).then(() => {
                  store.dispatch('user/resetToken').then(() => {
                      location.reload()
                  })
              })
            }
          }else{
            console.log('过期')
            MessageBox.confirm('是否重新登录?', '当前无登录用户信息', {
                confirmButtonText: '重新登录',
                cancelButtonText: '取消',
                type: 'warning'
            }).then(() => {
                store.dispatch('user/resetToken').then(() => {
                    location.reload()
                })
            })
          }
        })
      }
    }
    
    export default {
      namespaced: true,
      state,
      mutations,
      actions
    }
    
    
    第三步:src/permission.js 在拦截器中调用
    
    
    import router from './router'
    import store from './store'
    import { Message } from 'element-ui'
    import NProgress from 'nprogress' // progress bar
    import 'nprogress/nprogress.css' // progress bar style
    import { getToken } from '@/utils/auth' // get token from cookie
    import getPageTitle from '@/utils/get-page-title'
    NProgress.configure({ showSpinner: false }) // NProgress Configuration
    const whiteList = ['/login'] // no redirect whitelist
    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.roles && store.getters.roles.length > 0
          if (hasGetUserInfo) {
            next()
          } else {
            try {
              // get user info
              // await store.dispatch('user/getInfo')
              //调用获取动态的接口
              const {data} = await store.dispatch('user/getInfo')
              // 在这里获取异步路由
              const accessRoutes = await store.dispatch('permission/generateRoutes', data)
              // 调用router.addRoutes方法,将异步路由添加进去
              router.addRoutes(accessRoutes)
              // 在这动态添加最后的通配路由,确保先有动态路由、再有通配路由,解决动态路由刷新会跳转到404问题
              let lastRou = [{ path: '*', redirect: '/404' }]
              router.addRoutes(lastRou)
              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()
        }
      }
    })
    
    router.afterEach(() => {
      // finish progress bar
      NProgress.done()
    })
    
    
    
    
    展开全文
  • vue实现动态路由

    2021-05-28 15:38:43
    1、定义路由注册表表(注意定义数据返回不符合要求的数据) // 视图组件 const view = { Layout: () => import('@/layouts/Main.vue'), parentView: () => import('@/layouts/parentView'), } // 路由组件...

    1、定义路由注册表表(注意定义返回数据不符合要求的内容)

    // 视图组件
    const view = {
    	Layout: () => import('@/layouts/Main.vue'),
    	parentView: () => import('@/layouts/parentView'),
    }
    
    // 路由组件注册
    export const routerMap = {
    	'demo/home': {
    		title: '首页',
    		component: view.Layout,
    	},
    	'chdfc/code': {
    		title: '内容',
    		component: () => import('-----路径'),
    	},
    }
    
    

    2、解析后端返回的路由表生成符合vue-router的路由集合

    /**
     * 根据 路由集合 和 路由组件注册 解析路由
     * @param routesList 路由集合
     * @param routerMap 本地路由组件注册配置
     */
    export function parseRoutes(routesList, routerMap) {
    	let routes = []
    	routesList.forEach((item) => {
    		// 获取注册在 routerMap 中的 router,初始化 routeCfg
    		let router = undefined
    		let routeItem = {}
    
    		if (typeof item === 'string') {
    			router = routerMap[item]
    			routeItem = { path: router.path || item }
    		} else if (typeof item === 'object') {
    			router = routerMap[item.name]
    			routeItem = item
    		}
    
    		if (!router) {
    			console.warn(`can't find register for router ${routeItem.router}, please register it in advance.`)
    			router = typeof item === 'string' ? { path: item, name: item } : item
    		}
    
    		// 从 router 和 routeItem 解析路由
    		const route = {
    			path: routeItem.path || router.path,
    			name: routeItem.name || router.name,
    			component: router.component,
    			redirect: routeItem.homeUrl || router.homeUrl,
    			meta: {
    				title: routeItem.title || router.title || routeItem.meta?.title || router.meta?.title,
    				icon: routeItem.icon || router.icon || routeItem.meta?.icon || router.meta?.icon,
    				requiresAuth: routeItem.requiresAuth || router.requiresAuth || routeItem.meta?.requiresAuth || router.meta?.requiresAuth || false,
    				hideInBread: routeItem.hideInBread || router.hideInBread || routeItem.meta?.hideInBread || router.meta?.hideInBread || false,
    			},
    			children: router.children || [],
    		}
    
    		if (routeItem.children && routeItem.children.length > 0) {
    			route.children = parseRoutes(routeItem.children, routerMap)
    		}
    		routes.push(route)
    	})
    	return routes
    }
    
    /**
     * 合并路由
     * @param target {Route[]}
     * @param source {Route[]}
     * @returns {Route[]}
     */
    export function mergeRoutes(target, source) {
    	const routesMap = {}
    	target.forEach((item) => (routesMap[item.path] = item))
    	source.forEach((item) => (routesMap[item.path] = item))
    	return Object.values(routesMap)
    }
    
    

    3、静态路由和动态路由合并

    const router = createRouter({
    	history: createWebHashHistory(),
    	routes: mergeRoutes(routes, parseRoutes(menuData, routerMap)),
    })
    
    展开全文
  • 那么,我们可以在 Vue-Router 的路由路径中使用“动态路径参数”来达到这个效果 我们可以通过param和query两种方式获取动态参数 params的类型: 配置路由格式:/router/:id 传递的方式:在path后面跟上对应的值 ...

            我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如, 我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲 染。那么,我们可以在 Vue-Router 的路由路径中使用“动态路径参数”来达到这个效果

            我们可以通过param和query两种方式获取动态参数

    params的类型:

    1. 配置路由格式:/router/:id
    2. 传递的方式:在path后面跟上对应的值
    3. 传递后形成的路径:/router/123

    query的类类型:

    1. 配置路由格式:/router,也就是普通配置
    2. 传递的方式:对象中使用query的key作为传递方式
    3. 传递后形成的路径:/route?id=123
    展开全文
  • VueRouter定义路由参数定义方法请求路由数据引入模块最最最主要的还是全局路由导航守卫beforeEach 全局前置守卫router 模块VueRoter 版本问题router.addRoutes 已废弃:使用 router.addRoute() 代替。router.add...

    最近在写一个新项目,前端使用动态路由实现页面权限管控

    定义路由参数

    先定义一下需要后台传的路由参数(数据是自己mock的一个路由数据)

    {
      "router": [
        {
          "path": "/ProductDynamic",
          "component": "Layout",
          "redirect": "/ProductDynamic/TypeMachineQualityAnalys",
          "name": "ProductDynamic",
          "meta": {
            "title": "父菜单一",
            "icon": "el-icon-menu"
          },
          "children": [
            {
              "path": "TypeMachineQualityAnalys",
              "name": "TypeMachineQualityAnalys",
              "component": "ProductDynamic/TypeMachineQualityAnalys",
              "meta": {
                "title": "子菜单一"
              }
            },
            {
              "path": "TypeMachineCapacityAnalys",
              "name": "TypeMachineCapacityAnalys",
              "component": "ProductDynamic/TypeMachineCapacityAnalys",
              "meta": {
                "title": "子菜单二"
              }
            }
          ]
        },
       ]
      }
    

    定义方法请求路由数据

    引入模块
    import Layout from '@/layout';
    const _import = require('./modules/_import_' + process.env.NODE_ENV); //获取组件的方法
    
    /**
     * 處理路由json數據,轉換為前端路由需要的路由格式
     *
     * @param {*} asyncRouterMap 後臺的路由數據
     * @return {*}
     */
    function filterAsyncRouter(asyncRouterMap) {
      //遍历后台传来的路由字符串,转换为组件对象
      const accessedRouters = asyncRouterMap.filter(route => {
        if (route.component) {
          if (route.component === 'Layout') {
            //Layout组件特殊处理
            route.component = Layout; //引入组件
          } else {
            route.component = _import(route.component);
          }
        }
        if (route.children && route.children.length) {
          route.children = filterAsyncRouter(route.children);
        }
        return true;
      });
      return accessedRouters;
    }
    // 獲取系統菜單
    export const asyncRoutes = () => {
      return new Promise(resolve => {
        GetSysMenuTree().then(async res => {
          let result = res.data.router;
          const sysRoutes = filterAsyncRouter(result);
          resolve(sysRoutes);
        });
      });
    };
    

    最最最主要的还是全局路由导航守卫

    beforeEach 全局前置守卫

    路由导航这还存在在一些问题,后期会着手进行解决
    因为考虑到了用户可能会在登录后F5刷新以及退出登录等等的情况
    故使用了两个变量作判断
    本地存路由数据还需改进…(仅供参考)
    (有更好的解决方法,欢迎指教)

    router.beforeEach(async (to, from, next) => {
      // console.log("reouter1",router);
      // console.log('reouter2', router.getRoutes());
      NProgress.start();
      // 设置页面标题
      document.title = getPageTitle(to.meta.title);
      const hasToken = getToken();
      const userid = store.getters.userid;
      const isAddAsyncMenuRouter = store.getters.isAddAsyncMenuRouter; // 判斷是否初次登陸
      if (hasToken && userid) {
        if (isResetAsyncMenuRouter && isAddAsyncMenuRouter) {
          next({ replace: true });
          NProgress.done();
        } else {
          try {
            const accessRoutes = await asyncRoutes(); //獲取動態路由
            store.commit('user/SET_ROUTES', accessRoutes);
            // router.addRoutes(accessRoutes); //
            /**  */
            await accessRoutes.forEach(element => {
              // console.log(element)
              router.addRoute(element);
            });
    
            isResetAsyncMenuRouter = true;
            store.commit('user/SET_ISADDASYNCMENUROUTER', true);//判断是否是退出按钮触发退出
            // 设置replace: true,这样导航将不会留下历史记录
            next({ ...to, replace: true });
          } catch (error) {}
        }
      } else {
        if (['/login'].indexOf(to.path) !== -1) {
          next({ replace: true });
        } else {
          // 其他没有访问权限的页面被重定向到登录页面
          next(`/login?redirect=${to.path}`);
          NProgress.done();
        }
      }
    });
    

    router 模块

    定义两个js 文件
    在这里插入图片描述

    作用: 导出的实际格式为{default:组件名},require不支持默认导入,所以加载组件需要require().default

    _import_development
    module.exports = file => require('@/views/' + file + '/index.vue').default; // vue-loader
    
    _import_production
    module.exports = file => () => import('@/views/' + file + '/index.vue');
    

    VueRoter 版本问题

    router.addRoutes 已废弃:使用 router.addRoute() 代替。
    router.addRoute 添加一条新路由规则。如果该路由规则有 name,并且已经存在一个与之相同的名字,则会

    既然官网在新版的router 就废弃了,那我就直接使用了新版
    但是 新版的 router.addRoutes 还是可以使用的 ,至于为啥,这就没有过多的去了解了
    (希望有大佬教一教)

    新版的 router 与3.0版本的 的matcher 多了一些方法

    在这里插入图片描述

    router.getRoutes();  可以获取得到所有的路由参数
    
    (
    但出现了一个疑问,因为我在前端定义了4个静态路由,其他路由都是后台获取。
    而我在获取路由的时候打印的router 下的 options.routes  只显示的是静态路由
    看不到动态获取的路由,目前为止,为找出被放在了哪里
    router.getRoutes();  方法能获取到静态和动态的所有路由
    
    这就很疑惑了
    )
    

    在这里插入图片描述

    所遇到的问题

    在这里插入图片描述

    这里通过导航保护重定向的一个问题

    *问题的原因:

    • vue-router路由版本更新产生的问题,导致路由跳转失败抛出该错误;
    • 真正的原因是由于返回了一个Promise对象, 正常的跳转由then方法执行 当正常的路由跳转, 被"路由导航守卫"拦截并重新指定路由时,
    • 由于 this.$router.push() 返回的是Promise对象, 此时then方法不能正常执行, 无法跳转到指定路由, 就触发了该对象的捕获错误的方法,
    • throw抛出错误, 但并不影响程序功能

    解决:

    /**
     * 方法一: 降低 vue-router 版本
     * 更换vue-router版本为: npm i vue-router@3.0.7 -S
     */
    
    /**
     * 方法二:
     * 通过重写VueRouter原型对象上的push方法, 覆盖原来抛出异常的方法, "吞掉"异常
     *
     */
    const originalPush = Router.prototype.push;
    Router.prototype.push = function push(location, onResolve, onReject) {
      // 判断用户有没有传后面两个可选参数
      if (onResolve || onReject) return originalPush.call(this, location, onResolve, onReject);
      /* 
          默认底层: catch()方法代码  throw err : 抛出异常
          吞掉报错原理: 重写catch()方法,把默认底层的 throw err给去掉,就不会抛出异常
          */
      return originalPush.call(this, location).catch(err => err);
    };
    
    
    展开全文
  • Vue动态路由

    2020-12-20 10:53:17
    在router文件中先定义路由 import Vue from 'vue' import VueRouter from 'vue-router' //主页 import Home from '../views/Home' //详情 import Detail from "@/views/Detail/Detail"; Vue.use(VueRouter) //注册...
  • vue路由vue中通过路由跳转的三种方式标签路由 router-linkthis.$router.push()this.$router.replace()ps : this. $ router.push()和this. $ router.replace()的区别前端路由实现原理主要通过利用H5的history API实现...
  • 这里感谢router新加的addRoute(route:Array)方法,让我们可以进行相关的路由权限的配置。 路由的权限配置这里我介绍一下结合后端的方法。 首先我们需要对于路由信息进行数据库的存储,通过后端进行路由的权限控制 ...
  • 动态路由的理解 个人理解:动态路由就是把匹配某种模式下的路由映射到同个组件中,其实本质就是通过url进行传参 比如说:有一个商品Goods的组件,我们需要让不同的商品id都映射到这个组件中,此时就需要用到动态路由...
  • 一个webpack的api,通过执行require.context函数获取一个特定的上下文,主要用来实现自动化导入模块,在前端工程中,如果遇到从一个文件夹引入很多模块的情况,可以...文件的路径有2种,(1)简单的vue功能页面,直接挂在...
  • 我们经常需要把某个模式匹配到的所有路由,全都映射到同一个组件,例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染,那么我们可以在vue-router的路由路径中使用 “动态路由参数” ...
  • 公司项目做整理需要将前端vue项目菜单修改成动态菜单+动态路由。 1.动态路由 了解需求后查看了package.json使用的是Vue.js 官方的路由管理器:vue-router。 1. 查看vue-router官方文档发现vue-router有 添加新路由...
  • 假如这里的index.vue和login.vue是两个模块 创建路由模块 分别创建index模块和login模块的路由文件 index.routes.js children下则是这么模块的路由 export default { path: '/index', name: 'index', component...
  • 动态导航与动态路由绑定 在页面中左侧的菜单栏的数据是写死的,在实际场景中我们不可能这样做,因为菜单是需要根据登录用户的权限动态显示菜单的,也就是用户看到的菜单栏可能是不一样的,这些数据需要去后端访问...
  • 之前自学过vue-router,但都是停留在静态路由的层面,对于动态路由的实现一窍不通,刚好公司让维护一个使用了动态路由的项目,所以参照项目和网上的信息自己实现了一下,做个记录。 使用vuecli4.5创建的小项目,...
  • 我们不可能为每一个商品都定义一个独立的组件,而是把它们都映射到同一个组件,同时 url 后面的部分为动态变化的部分,我们会在设计路由的时候进行特殊的处理 ... { path: '/item/:itemId', name: 'item', ...
  • 定义路由 const routes = [ { path: '/first', name:'first', component:()=>import( '../components/first.vue' ) // component:first }, { path: '/second', name:'second', component:()=&
  • 能够构建出色的单页应用程序(SPA)是 Vue.js 最具有吸引力的功能之一。SPA 非常好,因为它们不需要在...在本教程中,我将介绍设置 Vue Router 的基础知识,并研究一些更高级的技术,例如:动态路由匹配导航挂钩(Na...
  • 但是如果没有配置当前路由第一个,这时候点击父级菜单,容易404,这个时候就需要我们动态配置redirect。 首先:我们先写一个函数,把当前路由的子路由传递进去,然后limits为本地所有有权限的路由,这个函数会返回...
  • 一、vue路由基础用法: 1 .安装 npm install vue-router --save 2 .main.js中 //Vue路由:引入 import VueRouter from 'vue-router' Vue.use(VueRouter) //Vue路由:引入并创建组件 import BYHome from './...
  • VueRouter 的参数中使用 children 配置,这样就可以很好的实现路由嵌套。 ① 为了演示,我们现在view文件夹下新建一个title1.vue和title2.vue用来存放不同的内容 ② 现在我们在router 》 index.js 中将这上面两个...
  • 创建一个Components.js文件来专门引入组件,然后在动态路由中存组件名,不存组件路径了,通过组件名绑定在Components.js中对应的组件。Components.jsexport default {Layout: () => import('@/views/layout/index...
  • ant design pro vue 动态路由 前后端详解前言流程图 前言 官方提供了两种实现权限的方法 官网地址 1:前端路由表写死(设置权限标识) 根据后端返回的权限标识生成路由表 2:动态路由 路由表由后端返回 前端根据返回的 ...
  • 文章目录Vue学习(路由定义、路由传参方式、子路由)-学习笔记路由定义(见下单个文件)路由传参方式二级路由动态面包屑路由组件路由中的props属性(了解)路由拦截 Vue学习(路由定义、路由传参方式、子路由)-学习...
  • (1)动态添加路由肯定用的是addRouter,在哪用? (2)vuex当中获取到菜单,怎样展示到界面 2.不管其他先试一下addRouter 找到router/index.js文件,内容如下,这是我自己先配置的登录路由 现在先不管请求到的菜单...
  • 定义路由时meta加上title定义标签页名称 constroutes=[ {path:'/',component:resolve=>require(['@/views/Home'],resolve), meta: { title: "页签一"}}, {path:'/login',component:resolve=>require(['@/...
  • 这是一个基于vuecli+element-plus共同搭建的一个开源vue3动态路由动态菜单开源框架,总体来说这个项目是非常优秀。你通过使用它直接实现动态路由和菜单管理功能,实现快速开发。支持二级菜单管理和嵌套路由管理。 ...
  • 前言vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径...首先在html中,引入vue-router.js和vue.js,用router-link触发路由跳转,router-link可以像a标签一样使用和定义样式router-view区域是路...
  • 在store/modules/permission.js中维护静态+动态路由权限,并在根目录下的permission.js实现导航守卫逻辑, 在/router/index.js中: import VueRouter from 'vue-router'; //constantRoutes 是静态路由,不需要...
  • <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> ...meta name="viewport" content="width=device-width, initial-scale=1.0">...script src="./vue.j

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 39,673
精华内容 15,869
关键字:

vue定义动态路由

vue 订阅