我有一个应用,用户可以在其中登录不同的角色,例如。 seller
,buyer
和admin
。
我想为每个用户在同一路径上显示仪表板页面,例如。 http://localhost:8080/dashboard
但是,每个用户将在不同的vue组件中定义不同的仪表板,例如。 SellerDashboard
,BuyerDashboard
和AdminDashboard
。
因此,基本上,当用户打开http://localhost:8080/dashboard
时,vue应用程序应根据用户角色(我存储在vuex中)加载不同的组件。同样,我想将其用于其他路线。例如,当用户转到个人资料页面http://localhost:8080/profile
时,应用程序应根据登录用户显示不同的个人资料组件。
因此,我希望所有用户角色具有相同的路由,而不是每个用户角色具有不同的路由。我不希望用户角色包含在url中,例如:http://localhost:8080/admin/profile
和http://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>
但是它不起作用,因为当我在Maximum call stack size exceeded
中调用next({ name: store.state.userRole })
时,在浏览器控制台中出现了beforeEnter
异常。例外是:
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)
因此没有呈现任何内容。
有没有办法解决这个问题?
答案 0 :(得分:3)
您可能想尝试以下解决方案:
<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}`)
}
}
这将使您能够使用动态组件,而不必事先导入所有cmps,而每次仅使用所需的一个。
答案 1 :(得分:0)
一种方法是使用dynamic component。您可能只有一个子路线,其组成部分也不是特定的(例如DashboardComponent
):
router.js
const routes = [
{
path: '/',
name: 'home',
children: [
{
path: '',
name: 'dashboard',
component: () => import('@/components/Dashboard')
}
]
}
]
components / 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>
答案 2 :(得分:0)
您遇到Maximum call stack size exceeded
异常是因为next({ name: store.state.userRole })
将触发另一个重定向并再次调用beforeEnter
,从而导致无限循环。
要解决此问题,可以检查to
参数,如果已经设置,则可以调用next()
确认导航,并且不会引起重定向。参见下面的代码:
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 })
}
},
答案 3 :(得分:0)
此类代码仅针对给定角色检索组件代码:
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;
答案 4 :(得分:0)
我遇到了同样的问题(我将Meteor JS与Vue JS一起使用),并且找到了使用 render函数来在同一路径上加载不同组件的方法。因此,您的情况应该是:
import Vue from "vue";
import VueRouter from "vue-router";
import Home from "../views/Home.vue";
import AdminDashboard from "../components/AdminDashboard";
import BuyerDashboard from "../components/BuyerDashboard";
import SellerDashboard from "../components/SellerDashboard";
import store from "../store";
Vue.use(VueRouter);
const routes = [
{
path: "/",
name: "home",
component: {
render: (h) => {
switch (store.state.userRole) {
case "admin":
return h(AdminDashboard);
case "buyer":
return h(BuyerDashboard);
case "seller":
return h(SellerDashboard);
default:
return h(Home);
}
}
}
}
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});
export default router;
请注意,此solution也有效,但仅在第一次时,如果您再次输入该路线,则它将保留最后加载的组件(您需要重新加载页面)。因此,使用render函数,它始终会加载新组件。
答案 5 :(得分:-1)
一种解决方法是为三种类型的用户创建三个单独的组件DashboardForAdmin
,DashBoardForSeller
和DashBoardForBuyer
。
然后使用mixin.js
export default {
data: function () {
return {
userType : "buyer"; // replace this with a function that returns "seller", "buyer", or "admin"
}
}
}
创建Vue组件DashboardContainer
基于mixin返回值呈现正确的仪表板组件
<template>
<div>
<div v-if="userType === 'admin'">
<DashboardForAdmin />
</div>
<div v-else-if="userType === 'buyer'">
<DashboardForBuyer />
</div>
<div v-else>
<DashboardForSeller />
</div>
</div>
</template>
<script>
import mixin from '@/mixin.js';
import DashboardForAdmin from '@/components/DashboardForAdmin.vue';
import DashBoardForSeller from '@/components/DashBoardForSeller.vue';
import DashBoardForBuyer from '@/components/DashBoardForBuyer.vue';
export default {
mixins: [mixin],
components: {
DashboardForAdmin, DashBoardForSeller, DashBoardForBuyer
},
};
</script>
现在您可以为DashboardContainer