ユーザーがさまざまな役割でログインできるアプリがあります。 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 routerを使用してこのシナリオを実装するにはどうすればよいですか?
子ルートとルートごとのガードbeforeEnter
の組み合わせを使用して、ユーザーロールに基づいたルートに解決してみました。以下はそのコードサンプルです。
in 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)
_
したがって、何もレンダリングされません。
これを解決する方法はありますか?
1つのアプローチは、 動的コンポーネント を使用することです。コンポーネントが特定されていない子ルートを1つ持つこともできます(例: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>
このようなコードは、特定のロールのコンポーネントコードのみを取得します。
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;
next({ name: store.state.userRole })
が別のリダイレクトをトリガーしてbeforeEnter
を再度呼び出し、無限ループが発生するため、_Maximum call stack size exceeded
_例外が発生します。これを解決するには、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 })
}
},
_