Ant Design Vue 动态路由

本文详细介绍了基于Vue.js的前端路由配置,包括main.js中引入router、router-index.js的基础路由设置、permission.js中的权限管理、以及动态路由生成。同时,展示了BasicLayout.vue的渲染过程,涉及全局布局、侧边菜单、路由视图等组件的使用。通过这些配置,实现了登录验证、页面跳转、404错误页面以及动态加载路由等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

main.js 引入 router

import router from './router'
new Vue({
  router,
  i18n,
  created: bootstrap,
  render: h => h(App)
}).$mount('#app')

router - index.js new Router

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

import { constantRouterMap } from '@/config/router.config'
const createRouter = () => new Router({
  mode: 'history',
  base:  "booking",
  scrollBehavior: () => ({ y: 0 }),
  routes: constantRouterMap
})

const router = createRouter()
export default router

配置基础路由

import { UserLayout} from '@/layouts'

export const constantRouterMap = [
  {
    component: UserLayout,
    path: '/',
    redirect: '/Login',
    children: [{
      path: '/Login',
      name:"Login",
      component: () => import('@/views/Home/Login')
    },
    {
      path: '/404',
      name:"404",
      component: () => import('@/views/exception/404'),
    },
    
    ]
  },
]

路由处理 - permission.js

import router from '@/router'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import { setDocumentTitle, domTitle } from '@/utils/domUtil'
import TokenCache from '@/utils/cache/TokenCache'
import OperatorCache from '@/utils/cache/OperatorCache'
import { initRouter } from '@/utils/routerUtil'
import defaultSettings from '@/config/defaultSettings'

NProgress.configure({ showSpinner: false }) // NProgress Configuration  

const whiteList = ['Login'] // no redirect whitelist

router.beforeEach((to, from, next) => {
  NProgress.start() // start progress bar
  to.meta && (typeof to.meta.title !== 'undefined' && setDocumentTitle(`${to.meta.title} - ${domTitle}`))
  // 已授权
  if (TokenCache.getToken()) {
    OperatorCache.init(() => {
      if (to.path === '/Home/Login') {
        next({ path: '/' })
        NProgress.done()
      } else { 
        initRouter(to, from, next).then(() => {
          const redirect = decodeURIComponent(from.query.redirect || to.path)
          //桌面特殊处理
          if (to.path == defaultSettings.desktopPath || to.path == '/404') {
            next()
          } else {
            if (to.path === redirect) {
              next()
            } else {
              // 跳转到目的路由
              next({ path: redirect })
            }
          }
        })
      }
    })
  } else {
    if (whiteList.includes(to.name)) {
      // 在免登录白名单,直接进入
      next()
    } else {
      next({ path: '/', query: { redirect: to.fullPath } })
      NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
    }
  }
})

router.afterEach(() => {
  NProgress.done() // finish progress bar
})

路由接口

import router from '@/router'
import { Axios } from '@/utils/plugin/axios-plugin'
import { BasicLayout, PageView } from '@/layouts'
import ProcessHelper from '@/utils/helper/ProcessHelper'
import defaultSettings from '@/config/defaultSettings'
import i18n from '../../config/i18n'
var uuid = require('node-uuid')

let inited = false
let addRouter = []

export const getAddRouter = () => {
  return addRouter
}

// 前端未找到页面路由(固定不用改)
const notFoundRouter = {
  path: '*',
  redirect: '/404',
  hidden: true
}

// 开发模式额外路由
const devRouter = [
  {
    title: '开发',
    icon: 'code',
    children: [
      {
        path: '/Base_Manage/Base_DbLink/List',
        title: '数据库连接'
      }
    ]
  },
]
//初始化
export const initRouter = (to, from, next) => {
  return new Promise((res, rej) => {
    if (inited) {
      res()
    } else {
      generatorDynamicRouter().then(dynamicRouter => {
        router.addRoutes(dynamicRouter)
        addRouter = dynamicRouter
        inited = true
        //路由缓存
        localStorage.setItem('routers',dynamicRouter);
        next({ ...to, replace: true })
      })
    }
  })
}

/**
 * 获取路由菜单信息
 * @returns {Promise<any>}
 */
const generatorDynamicRouter = () => {
  return new Promise((resolve, reject) => {
    // ajax
    getRouterByUser().then(res => {
        let allRouters = []

        //首页根路由
        let rootRouter = {
          // 路由地址 动态拼接生成如 /dashboard/workplace
          path: '/',
          redirect: defaultSettings.desktopPath,
          // 路由名称,建议唯一
          name: uuid.v4(),
          // 该路由对应页面的 组件
          component: BasicLayout,
          // meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
          meta: { title: '首页' },
          children: []
        }
        allRouters.push(rootRouter)

        if (!ProcessHelper.isProduction()) {
          res.push(...devRouter)
        }
        //格式化路由
        rootRouter.children = generator(res)
        allRouters.push(notFoundRouter)

        //返回组装后的路由
        resolve(allRouters)
      })
      .catch(err => {
        reject(err)
      })
  })
}

/**
 * 获取后端路由
 * @returns {Promise}
 */
const getRouterByUser = () => {
  return new Promise((resolve, reject) => {
    Axios.post('/Home/GetMenu', {}).then(resJson => {
      if (resJson.Success) {
        resolve(resJson.Data)
      }
    })
  })
}

/**
 * 格式化 后端 结构信息并递归生成层级路由表
 *
 * @param routerMap
 * @param parent
 * @returns {*}
 */
const generator = (routerMap, parent) => {
  return routerMap.map(item => {
    let hasChildren = item.children && item.children.length > 0
    let component = {}
    if (hasChildren) {
      component = PageView
    } else if (item.path) {
      component = () => import(`@/views${item.path.replace(new RegExp(/\/\:.*$/), '')}`)
    }
    let currentRouter = {
      path: '',
      // 路由名称,建议唯一
      name: uuid.v4(),
      // 该路由对应页面的 组件
      component: component,
      // meta: 页面标题, 菜单图标, 页面权限(供指令权限用,可去掉)
      // 这里添加了国际化
      meta: { title: i18n.t(`menu.${item.Lan_id}`), icon: item.icon || undefined }
    }

    //有子菜单
    if (hasChildren) {
      currentRouter.path = `/${uuid.v4()}`
    } else if (item.path) {
      //页面
      currentRouter.path = item.path
      currentRouter.path = currentRouter.path.replace('//', '/')
    }

    // 重定向
    item.redirect && (currentRouter.redirect = item.redirect)
    // 是否有子菜单,并递归处理
    if (hasChildren) {
      // Recursion
      currentRouter.children = generator(item.children, currentRouter)
    }
    return currentRouter
  })
}

BasicLayout.vue的渲染

<template>
  <a-layout :class="['layout', device]">
    <!-- SideMenu -->
    <a-drawer
      v-if="isMobile()"
      placement="left"
      :wrapClassName="`drawer-sider ${navTheme}`"
      :closable="false"
      :visible="collapsed"
      @close="drawerClose"
    >
      <side-menu
        mode="inline"
        :menus="menus"
        :theme="navTheme"
        :collapsed="false"
        :collapsible="true"
        @menuSelect="menuSelect"
      ></side-menu>
    </a-drawer>

    <side-menu
      v-else-if="isSideMenu()"
      mode="inline"
      :menus="menus"
      :theme="navTheme"
      :collapsed="collapsed"
      :collapsible="true"
    ></side-menu>

    <a-layout
      :class="[layoutMode, `content-width-${contentWidth}`]"
      :style="{ paddingLeft: contentPaddingLeft, minHeight: '100vh' }"
    >
      <!-- layout header -->
      <global-header
        :mode="layoutMode"
        :menus="menus"
        :theme="navTheme"
        :collapsed="collapsed"
        :device="device"
        @toggle="toggle"
      />

      <!-- layout content -->
      <a-layout-content
        :style="{ height: '100%', margin: '24px 24px 0', paddingTop: fixedHeader ? '64px' : '0' }"
      >
        <multi-tab v-if="multiTab"></multi-tab>
        <transition name="page-transition">
          <!-- <route-view /> -->
          <div class="content">
            <div class="page-header-index-wide">
              <slot>
                <!-- keep-alive  -->
                <keep-alive v-if="multiTab">
                  <router-view ref="content" />
                </keep-alive>
                <router-view v-else ref="content" />
              </slot>
            </div>
          </div>
        </transition>
      </a-layout-content>

      <!-- layout footer -->
      <!-- <a-layout-footer>
        <global-footer />
      </a-layout-footer>-->

      <!-- Setting Drawer (show in development mode) -->
      <!-- <setting-drawer v-if="!production"></setting-drawer> -->
    </a-layout>
  </a-layout>
</template>

<script>
import { triggerWindowResizeEvent } from '@/utils/util'
import { mapState, mapActions } from 'vuex'
import { mixin, mixinDevice } from '@/utils/mixin'
import config from '@/config/defaultSettings'

import RouteView from './RouteView'
import MultiTab from '@/components/MultiTab'
import SideMenu from '@/components/Menu/SideMenu'
import GlobalHeader from '@/components/GlobalHeader'
import GlobalFooter from '@/components/GlobalFooter'
// import SettingDrawer from '@/components/SettingDrawer'
import { getAddRouter } from '@/utils/routerUtil'

export default {
  name: 'BasicLayout',
  mixins: [mixin, mixinDevice],
  components: {
    RouteView,
    MultiTab,
    SideMenu,
    GlobalHeader,
    GlobalFooter
    // SettingDrawer
  },
  data() {
    return {
      production: config.production,
      collapsed: false,
      menus: []
    }
  },
  computed: {
    ...mapState({
      // 动态主路由
      mainMenu: state => getAddRouter()
    }),
    contentPaddingLeft() {
      if (!this.fixSidebar || this.isMobile()) {
        return '0'
      }
      if (this.sidebarOpened) {
        return '220px'
      }
      return '80px'
    }
  },
  watch: {
    sidebarOpened(val) {
      this.collapsed = !val
    }
  },
  created() {
    //menus赋值
    this.menus = this.mainMenu.find(item => item.path === '/').children
    this.collapsed = !this.sidebarOpened
  },
  mounted() {
    const userAgent = navigator.userAgent
    if (userAgent.indexOf('Edge') > -1) {
      this.$nextTick(() => {
        this.collapsed = !this.collapsed
        setTimeout(() => {
          this.collapsed = !this.collapsed
        }, 16)
      })
    }
  }
}
</script>

### 回答1: Ant Design Pro Vue 动态路由是指在运行时根据用户权限或其他条件动态生成路由。这种方式可以使应用程序更加灵活和可扩展,可以根据不同的用户角色或权限来展示不同的页面或菜单。在 Ant Design Pro Vue 中,可以通过配置路由表和权限控制来实现动态路由。具体实现方式可以参考官方文档或相关教程。 ### 回答2: Ant Design Pro Vue 是一个基于 Vue.js 的企业级中后台前端开发框架,它能够极大地提高开发效率和页面美观度。动态路由是其一个非常重要的功能,可以让前端路由的配置在后台管理系统中进行动态修改和生成,减少了前后端的耦合性。下面将对动态路由的使用进行详细介绍。 动态路由的概念: 动态路由是指根据后台返回的数据动态生成前端路由配置,前端可以通过该配置进行页面的访问。具体来说,当用户在前端操作时,前端会发起请求到后台,后台返回一个包含路由信息的 JSON 数据,前端负责解析该数据并进行路由配置。 实现步骤: 1.首先在路由配置文件中定义一个动态路由所在的组件。 2.在页面初始加载时,通过 Ajax 请求后台路由信息。 3.将后台返回的路由信息动态生成配置,并添加到路由表中。 4.当用户访问页面时,根据请求的路径进行路由匹配,并将匹配到的组件渲染到页面中。 优点: 1.动态路由配置可以让前端和后端的路由分离,减少了前后端的耦合性。 2.简化了前端路由的管理,后台管理员可以通过后台管理系统进行路由配置,而不需要修改前端代码。 3.动态路由可以提高前端的开发效率,让前端开发人员更加专注于界面和交互的开发。 总之,Ant Design Pro Vue 动态路由是一个非常重要的功能,它大大提高了前端开发的效率和可维护性,也方便了后台管理员进行路由配置。因此,大家在使用 Ant Design Pro Vue 开发企业级中后台系统时,一定要熟练掌握其动态路由的使用方法。 ### 回答3: Ant Design Pro Vue 是一个基于 Vue.js 技术栈的企业级中后台前端解决方案。它使用 Ant Design UI 组件库,并提供了一系列的经过优化的业务逻辑组件和样式,可以帮助开发人员更快速地完成中后台项目的开发。 动态路由Ant Design Pro Vue 的一个重要特性之一,它可以让开发人员根据业务需求动态地生成路由。这个特性的优点在于它可以大大减少开发人员的工作量,提高开发效率。具体来说,动态路由可以帮助开发人员实现以下几方面的需求: 1. 针对不同的角色或权限级别,动态生成不同的路由配置。这样,可以保证不同用户只能访问其具备权限的资源。 2. 根据业务需求动态生成菜单配置。这样,可以方便地根据业务需求灵活地修改菜单展示。 3. 当前路由路径不存在时,可以根据业务需求自动跳转到指定的路由。这样,可以避免用户访问不存在的路由时出现问题。 除了以上几点之外,动态路由还具有以下几个优点: 1. 可以更加灵活地处理路由跳转逻辑,使得开发人员可以更方便地处理复杂的业务逻辑。 2. 可以更好地适应企业级前端项目开发的需求,使得项目可以更容易地扩展和维护。 总之,Ant Design Pro Vue动态路由特性可以帮助开发人员快速构建出高质量的企业级中后台前端项目。它的灵活性和可扩展性可以满足各种不同项目的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值