web-dev-qa-db-fra.com

Vue router - comment avoir plusieurs composants chargés sur le même chemin d'accès en fonction du rôle de l'utilisateur?

J'ai une application où l'utilisateur peut se connecter dans différents rôles, par exemple. seller, buyer et admin. Pour chaque utilisateur, je voudrais afficher la page du tableau de bord sur le même chemin, par exemple. http://localhost:8080/dashboard Cependant, chaque utilisateur aura un tableau de bord différent défini dans différents composants vue, par exemple. SellerDashboard, BuyerDashboard et AdminDashboard.

Donc, fondamentalement, lorsque l'utilisateur ouvre http://localhost:8080/dashboard vue l'application devrait charger un composant différent en fonction du rôle de l'utilisateur (que je stocke dans vuex). De même, j'aimerais avoir ceci pour Par exemple, lorsque l'utilisateur accède à la page de profil, l'application http://localhost:8080/profile doit afficher un composant de profil différent en fonction de l'utilisateur connecté.

Je voudrais donc avoir la même route pour tous les rôles d'utilisateurs par opposition à avoir une route différente pour chaque rôle d'utilisateur, par exemple. Je ne veux pas que le rôle utilisateur soit contenu dans l'URL comme suit: http://localhost:8080/admin/profile Et http://localhost:8080/seller/profile Etc ...

Comment puis-je implémenter ce scénario avec le routeur vue?

J'ai essayé d'utiliser une combinaison d'itinéraires enfants et de garde par itinéraire beforeEnter pour résoudre un itinéraire basé sur le rôle de l'utilisateur. Voici un exemple de code de cela:

dans 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

dans 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 contient la vue du routeur parent pour les routes de niveau supérieur, par exemple. mappez / au composant Home et /about au composant About:

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

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

Et Home.vue contient router-view Imbriqué pour différents composants basés sur les rôles de l'utilisateur:

<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>

Mais cela ne fonctionne pas car j'obtiens l'exception Maximum call stack size exceeded Dans la console du navigateur lorsque j'appelle next({ name: store.state.userRole }) dans beforeEnter. L'exception est:

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)

et ainsi rien n'est rendu.

Existe-t-il un moyen de résoudre ce problème?

6
mlst

Une approche consisterait à utiliser un composant dynamique . Vous pouvez avoir une seule route enfant dont le composant est également non spécifique (par exemple DashboardComponent):

router.js

const routes = [
  {
    path: '/',
    name: 'home',
    children: [
      {
        path: '',
        name: 'dashboard',
        component: () => import('@/components/Dashboard')
      }
    ]
  }
]

composants/Dashboard.vue

<template>
  <!-- wherever your component goes in the layout -->
  <component :is="dashboardComponent"></component>
</template>

<script>
import AdminDashboard from '@/components/Admin/AdminDashboard'
import SellerDashboard from '@/components/Seller/SellerDashboard'
import BuyerDashboard from '@/components/Buyer/BuyerDashboard'

const RoleDashboardMapping = {
  admin: AdminDashboard,
  seller: SellerDashboard,
  buyer: BuyerDashboard
}

export default {
  data () {
    return {
      dashboardComponent: RoleDashboardMapping[this.$store.state.userRole]
    }
  }
}
</script>
0
Matt U

Ce code récupère le code du composant uniquement pour un rôle donné:

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: () => {
      switch (store.state.userRole) {
        case "admin":
          return import("../components/AdminDashboard");
        case "buyer":
          return import("../components/BuyerDashboard");
        case "seller":
          return import("../components/SellerDashboard");
        default:
          return Home;
      }
    }
  }
];

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

export default router;
0
Gander

Vous rencontrez l'exception Maximum call stack size exceeded Car la next({ name: store.state.userRole }) déclenchera une autre redirection et appellera à nouveau le beforeEnter et entraînera ainsi une boucle infinie. Pour résoudre ce problème, vous pouvez vérifier le paramètre to, et s'il est déjà défini, vous pouvez appeler next() pour confirmer la navigation, et cela ne provoquera pas de redirection. Voir le code ci-dessous:

beforeEnter: (to, from, next) => {
  // Helper to inspect the params.
  console.log("to", to, "from", from)

  // this is just an example, in your case, you may need
  // to verify the value of `to.name` is not 'home' etc. 
  if (to.name) { 
    next();
  } else {
    next({ name: store.state.userRole })
  }
},
0
lenglei