VUE路由器-如何根据用户角色将多个组件加载到同一路由路径上?

2022-03-03 00:00:00 javascript vue.js vue-router vuex

我有应用程序,用户可以登录在不同的角色,例如。sellerbuyeradmin。 对于每个用户,我想在相同的路径上显示仪表板页面,例如。http://localhost:8080/dashboard 但是,每个用户将在不同的VUE组件中定义不同的仪表板,例如,SellerDashboardBuyerDashboardAdminDashboard

因此,基本上,当用户打开http://localhost:8080/dashboard时,VUE应用程序应该根据用户角色加载不同的组件(我将其存储在VUEX中)。同样地,我想把这张票换成其他路线的票。例如,当用户转到配置文件页面http://localhost:8080/profile时,应用程序应根据登录的用户显示不同的配置文件组件。

所以我希望所有用户角色都有相同的路由,而不是每个用户角色都有不同的路由,例如。我不希望用户角色包含在URL中,如下所示:http://localhost:8080/admin/profilehttp://localhost:8080/seller/profile等.

如何使用VUE路由器实施此方案?

我尝试使用子路由和每路由防护的组合beforeEnter来解析为基于用户角色的路由。以下是其中的一个代码示例:

在router.js中:

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import store from '@/store'

Vue.use(VueRouter)

const routes = [
  {
    path: '/',
    name: 'home',
    component: Home,

    beforeEnter: (to, from, next) => {
      next({ name: store.state.userRole })
    },

    children: [
      {
        path: '',
        name: 'admin',
        component: () => import('@/components/Admin/AdminDashboard')
      },
      {
        path: '',
        name: 'seller',
        component: () => import('@/components/Seller/SellerDashboard')
      },
      {
        path: '',
        name: 'buyer',
        component: () => import('@/components/Buyer/BuyerDashboard')
      }
    ]
  },
]

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})

export default router

在store.js:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    userRole: 'seller' // can also be 'buyer' or 'admin'
  }
})

App.vue包含顶级路由的父路由视图,例如。将/映射到Home组件和/about映射到About组件:

<template>
  <router-view/>
</template>

<script>
export default {
  name: 'App',
}
</script>

和Home.vue包含不同用户基于角色的组件的嵌套router-view

<template>
  <div class="home fill-height" style="background: #ddd;">
    <h1>Home.vue</h1>
    <!-- nested router-view where user specific component should be rendered -->
    <router-view style="background: #eee" />
  </div>
</template>

<script>
export default {
  name: 'home'
}
</script>

但它不起作用,因为我在beforeEnter中调用next({ name: store.state.userRole })时,在浏览器控制台得到Maximum call stack size exceeded异常。例外情况是:

vue-router.esm.js?8c4f:2079 RangeError: Maximum call stack size exceeded
    at VueRouter.match (vue-router.esm.js?8c4f:2689)
    at HTML5History.transitionTo (vue-router.esm.js?8c4f:2033)
    at HTML5History.push (vue-router.esm.js?8c4f:2365)
    at eval (vue-router.esm.js?8c4f:2135)
    at beforeEnter (index.js?a18c:41)
    at iterator (vue-router.esm.js?8c4f:2120)
    at step (vue-router.esm.js?8c4f:1846)
    at runQueue (vue-router.esm.js?8c4f:1854)
    at HTML5History.confirmTransition (vue-router.esm.js?8c4f:2147)
    at HTML5History.transitionTo (vue-router.esm.js?8c4f:2034)

,因此不会呈现任何内容。

有没有办法可以解决这个问题?


解决方案

您可能需要尝试解决此解决方案:

<template>
  <component :is="compName">
</template>
data: () {
 return {
      role: 'seller' //insert role here - maybe on `created()` or wherever
 }
},
components: {
 seller: () => import('/components/seller'),
 admin: () => import('/components/admin'),
 buyer: () => import('/components/buyer'),
}

或者如果您愿意,也许可以更整洁一些(结果相同):

<template>
  <component :is="loadComp">
</template>
data: () => ({compName: 'seller'}),
computed: {
 loadComp () {
  const compName = this.compName
  return () => import(`/components/${compName}`)
 }
}

这将使您可以使用动态组件,而不必预先导入所有CMP,而只需每次使用所需的一个。

相关文章