【问题标题】:Is there a way to load different views for one route depending on user role?有没有办法根据用户角色为一条路线加载不同的视图?
【发布时间】:2020-07-12 13:26:58
【问题描述】:

如果我想根据角色将主页路径“/”用于不同的视图,是否有一些实现?就像如果您是授权用户,您将看到MainAuth,如果您是访客,您将看到MainGuest?这是一些可以帮助我解释的代码。

const routes = [
  {
    path: '/',
    name: 'main_auth',
    component: MainAuth,
    meta: {
      requiresAuth: true
    }
  },
  {
    path: '/',
    name: 'main_guest',
    component: MainGuest,
    meta: {
      requiresGuest: true
    }
  }
]

对于这个例子,它只加载我声明的第一个路径,无论我是访客还是用户。更具体地说,我在主路径“/”上有一个登录/注册模块,我想在登录后在同一路径“/”上加载授权用户页面。

【问题讨论】:

    标签: javascript vue.js vuejs2 vue-router vue-cli


    【解决方案1】:

    您可以使用 beforeEach 方法将用户重定向到另一个路由。

    例子:

    router.beforeEach((to, from, next) => {
      // Determine if the route requires Authentication
      const requiresAuth = to.matched.some(x => x.meta.requiresAuth);
      const user = auth.getUser();
    
      // If it does and they are not logged in, send the user to "/login"
      if (requiresAuth && !user) {
        next("/login");
      } else {
        // Else let them go to their next destination
        next();
      }
    });
    

    【讨论】:

    • 是的,它有效,但这并不是我真正在谈论的。我在主页“/”上登录/注册,我想在同一路径“/”上加载授权用户页面。因此,如果我是访客,我需要跳过用户的路线并为我的角色加载视图,反之亦然。
    • 我不知道是否可以声明两条相同的路由,另一种实现方式是在一个路由中使用props:isAuthorized,然后使用这个prop值进行条件渲染(v -if, v-show)
    • 这实际上是这个答案向您展示的:如果它是客人,则跳过路线(即重定向)。此代码:next("/login") 是重定向。
    • @Dan,不,我不需要重定向。我在主路径'/'上有登录/注册视图,我想在唱歌后在同一主路径'/'上显示授权用户页面视图。所以我需要像“重定向”到'/',但它只给出无论如何,在路由器中声明的第一个主路径。
    【解决方案2】:

    由于您只想使用一个路径,您可以使用基本路由并在组件本身中完成工作。路线:

    const routes = [
      {
        path: '/',
        name: 'main',
        component: Main,
      }
    ]
    

    Main查看组件:

    <template>
      <div>
        <Auth v-if="!loggedIn" />
        <MainContent v-else />
      </div>
    </template>
    

    Auth组件:

    <template>
      <div>
        <Login v-if="showLogin" />
        <Register v-else />
      </div>
    </template>
    

    这样,您可以检查用户是否从Main 视图组件登录并显示Auth 组件或主要内容。

    然后,在Auth 组件中,您使用一个切换开关,允许用户在LoginRegister 组件之间切换。

    【讨论】:

    • 看起来可行的解决方案,谢谢,我会尽快检查。这样做而不是将身份验证模块和用户页面路由到不同的路由是一种不好的做法吗?
    • 不客气。我认为这只是一个偏好问题。主要影响可能是您无法直接链接到登录或注册视图,因为它们没有自己的路由。
    【解决方案3】:

    这里有 3 个选项:

    1.简单计算视图

    要允许单个路由显示任意数量的条件视图,请使用计算组件。

    注册视图:

    import Vue from 'vue'
    
    import ViewDefault from '/views/Default.vue'
    Vue.component('view-default', ViewDefault )
    
    import ViewAuth from '/views/Auth.vue'
    Vue.component('view-auth', ViewAuth )
    
    import ViewGuest from '/views/Guest.vue'
    Vue.component('view-guest', ViewGuest)
    

    路线:

      {
        path: '/',
        name: 'index',
        component: ViewDefault
      },
    

    查看Default.vue

    <template>
      <component :is="view"></component>
    </template>
    
    <script>
    
    export default {
    
      name: 'view-default',
    
      computed: {
    
       view() {
         return this.isAuthenticated ? 'view-auth' : 'view-guest'
       }  
    
      }
    
    }
    
    </script>
    

    您将能够在view() 中创建任意数量的条件检查。


    2。条件命名视图(概念未尝试)

    我会考虑尝试使用命名视图,我相信您可以使用用户和访客版本双重查看许多路径,我还没有尝试过:

    https://router.vuejs.org/guide/essentials/named-views.html

    <template>
    
      <div>
    
        <template v-if="isAuthenticated">
          <router-view name="authed"/>
        </template>
      
        <template v-else>
          <router-view/>
        </template>
    
      </div>
    
    </template>
    

    Router

    
    const router = new VueRouter({
      routes: [
        {
          path: '/',
          components: {
            default: MainGuest,
            authed: MainAuth,
          }
        }
      ]
    })
    
    

    3.计算布局

    但是...我个人使用 I/O 阻塞布局,计算 layout

    在计算包含&lt;router-view&gt;的最终布局之前,我会检查各种应用程序状态,这些状态根据条件控制显示哪些布局。

    我让路由器路径通过meta 数据指定自定义布局,设置备用布局,否则回退到默认布局。

    Router

      {
        name: 'index',
        path: '/',
        meta: {
          title: 'Welcome',
          guard: 'auth'
        },
        component: import('@/views/welcome')
      },
    
      {
        name: 'settings',
        path: '/settings',
        meta: {
          title: 'Account Settings',
          layout: 'settings',
          guard: 'auth'
        },
        component:  import('@/views/account-settings')
      }
    

    App.vue

    <template>
    
      <div id="app" v-cloak :class="$root.layout">
    
        <transition name="component-fade" mode="out-in">
          <component :is="$root.layout"/>
        </transition>
    
      </div>
    
    </template>
    

    main.js

    
    import Vue from 'vue'
    import router from './router'
    import store from './store'
    import '@/views/layouts'
    import App from './App'
    
    
    // Use Vuex to store states, `axios` calls and response `interceptors` are used to `commit` computed mapped state conditions globally.
    
    import { mapState, mapGetters } from 'vuex'
    
    Vue.mixin({
    
      computed: {
    
        ...mapState(['user', 'isAuthenticating', 'isOffline']),
    
        ...mapGetters(['isAuthenticated']),
    
      }
    
    })
    
    new Vue({
    
      el: '#app'
      render: h => h(App),
      store,
      router,
    
      computed: {
    
        layout () { // could move this to vuex and access via mapGetters...
    
          if (this.isOffline) {
            return 'layout-offline'
          }
    
          if (this.isAuthenticating) {
            return 'layout-authenticating'
          }
    
          if (this.$route.meta.hasOwnProperty('guard')) {
    
            if(this.$route.meta.guard === 'auth' && !this.isAuthenticated) {
              return 'layout-login'
            }
    
          }
    
          // If current route has a preferred layout use it else fallback to `layout-default`
          let layout = this.$route.meta.layout || 'default'
    
          return `layout-${layout}`
        }
    
      },
    
    })
    
    
    

    views/layouts/index.js

    import Vue from 'vue'
    
    import LayoutOffline from './layout-offline')
    import LayoutAuthenticating from './layout-authenticating')
    import LayoutLogin from './layout-login')
    
    import LayoutDefault from './layout-default')
    import LayoutSettings from './layout-settings')
    
    Vue.component('layout-offline', LayoutOffline)
    Vue.component('layout-authenticating', LayoutAuthenticating)
    Vue.component('layout-login', LayoutLogin)
    
    Vue.component('layout-default', LayoutDefault)
    Vue.component('layout-settings', Layoutsettings)
    
    

    只有layout-default 或任何指定自定义布局的路由器路径应包含&lt;router-view&gt; 以及页眉、页脚、侧边栏等...

    您可以将其与名称视图混合使用,不同的计算布局可以为相同的 path 显示不同的名称 router-view

    【讨论】:

    • 我尝试了第二个选项,并且可以确认它有效。干杯。
    猜你喜欢
    • 1970-01-01
    • 2021-01-09
    • 2019-02-17
    • 2014-03-02
    • 2020-08-16
    • 1970-01-01
    • 2011-07-25
    • 2019-08-17
    • 1970-01-01
    相关资源
    最近更新 更多