Vue.jsのナビゲーションガードを使って、ユーザ別のトップページに画面遷移させる。

最近流行りのVue.jsを使ってWeb開発をしているのですが、その過程でVue.jsのナビゲーションガードを使って、ユーザ別のトップページに遷移させる、というのを実装しました。
イメージとしては、ヘッダーに共通の「Home」ボタンがあって、これを押下した際に、ユーザ別のトップページに遷移させるというのものです。


#Vue.routerとは
Vue.jsの拡張ライブラリで、これを使うとシングルページアプリケーション(SPA)を構築することが出来ます。
シングルページアプリケーションは、複数のページ使ってを画面遷移をするのではなく、Webページ上の要素を置き換えることで画面遷移を実現する、というものです。

#ナビゲーションガードとは
[公式](https://router.vuejs.org/ja/guide/advanced/navigation-guards.html#%E3%82%B0%E3%83%AD%E3%83%BC%E3%83%90%E3%83%AB%E3%82%AC%E3%83%BC%E3%83%89)にも説明はありますが、簡単に説明します。ナビゲーションガードを使うと、画面遷移する際に処理を加えることができ、遷移先を変更したりすることが出来ます。


#(その前に・・・)前提条件

今回はこのナビゲーション機能を使って、ヘッダーにあるホームボタンを押した際に、ユーザ別(一般ユーザ、管理者ユーザなど)のトップページに遷移させる処理を実装していきます。

が、その前に一つ前提条件があります。それはログインした際に、Vuexにログイン情報を保持しておくということです。
Vuexについての知識が浅い方はまず、それについて勉強してください。今回はログインの際に、「ログインID」、「パスワード」、「role」の3つの情報を、Vuexに保存しています。
なおこの「role」プロパティは1~3の値を取り、この値を見て、どのユーザー(一般ユーザーなのか管理ユーザーなのか)を判断していきます。


#ユーザ別のトップページに遷移する
それでは実装していきましょう。まずはVue.routerの設定です。

```main.js
 router.beforeEach((to, from, next) => {
//Vuexに保持しているloginオブジェクトを取得
  const currentUser = store.state.login
//遷移先が/loginのときは、Vuexの値を空にする
  if (currentUser.role) {
    if (to.path == '/login') {
      store.commit("loginUser", {})
    }
//roleプロパティによって遷移先を振り分け
    if (to.path == '/home') {
      if (currentUser.role == 1) {
        next({
          path: '/A01',
        })
      }else if(currentUser.role == 2){
        next({
          path: '/B01'
        })
      }else if(currentUser.role == 3){
        next({
          path: '/C01'
        })
      } else {
        next({
          path: '/login',
        })
      }    
    }    
  }
})
```
遷移先を空のページである、/homeに一旦指定しておき、実際の遷移先は、Vuexに保持しているloginオブジェクトを取り出し、そのroleプロパティの値によって、振り分けています。roleプロパティが存在しない際は、ログインページに遷移するようにしています。

また、空のページとして指定する/homeですが、index.jsに最低限pathを指定しないと動きません。(nameとcomponentは記述しなくてもよい。なので、importもしなくてよい。)

どういうことかというと、index.jsに以下の記述が最低限必要ということです。

```index.js

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/login',
      name: 'Login',
      component: Login,
      meta: {
        isPublic: true  
      }
    },
    {
      path: '/A01',
      name: 'A01',
      component: A01
    },
    {
      path: '/B01',
      name: 'B01',
      component: B01
    },
    {
      path: '/C01',
      name: 'C01',
      component: C01
    },
//ここの記述が最低限必要。
    {
      path: '/home'
    },
    {
      path: '*', 
      redirect: '/Login'
    }
  ]
})

```


また、リダイレクト機能も実装しました。リダイレクトに関しては[こちら](https://qiita.com/masatomix/items/5316acdb5980289e5cc2#%E7%94%BB%E9%9D%A2%E3%81%AB%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9%E3%81%97%E3%81%9F%E3%81%A8%E3%81%8D%E3%81%AB%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E6%B8%88%E3%81%BF%E3%81%A7%E3%81%AA%E3%81%84%E5%A0%B4%E5%90%88%E3%81%AF%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E7%94%BB%E9%9D%A2%E3%82%92%E8%A1%A8%E7%A4%BA%E3%81%97%E8%AA%8D%E8%A8%BC%E3%81%97%E3%81%9F%E3%82%89%E8%A9%B2%E5%BD%93%E7%94%BB%E9%9D%A2%E3%81%B8%E9%81%B7%E7%A7%BB%E3%81%99%E3%82%8B)を参考に実装しました。



```main.js
 router.beforeEach((to, from, next) => {
  const currentUser = store.state.login

//省略

  if (to.matched.some(record => record.meta.isPublic)) {
    next()
  } else {
    if (currentUser.role) {
      next()
    } else {
      next({
        path: '/login',
        query: {
          redirect: to.path
        }
      })
    }
  }
})
```



全体としてはこんな感じです。

```main.js
 router.beforeEach((to, from, next) => {
  const currentUser = store.state.login
  if (currentUser.role) {
    if (to.path == '/login') {
      store.commit("loginUser", {})
    }
    if (to.path == '/home') {
      if (currentUser.role == 1) {
        next({
          path: '/A01',
        })
      }else if(currentUser.role == 2){
        next({
          path: '/B01'
        })
      }else if(currentUser.role == 3){
        next({
          path: '/C01'
        })
      } else {
        next({
          path: '/login',
        })
      }    
    }    
  }

  if (to.matched.some(record => record.meta.isPublic)) {
    next()
  } else {
    if (currentUser.role) {
      next()
    } else {
      next({
        path: '/login',
        query: {
          redirect: to.path
        }
      })
    }
  }
})
```

これで、画面遷移する際の準備が出来ました。

続いて画面側の実装をします。既にお分かりの方もいるかもしれませんが、ヘッダーのホームボタンを押した際、遷移先に/homeを指定すれば、ユーザ毎のトップページに遷移先を振り分けてくれます。

```Header.vue

<template>
  <div  class="container">
    
  <span v-if="this.$route.name !== 'A01' && this.$route.name !== 'B01' && this.$route.name !== 'C01' && this.$route.name !== 'Login'">
    <h3 @click="home" class="home"><font-awesome-icon icon="home" /></h3></span> 
      <span v-if="this.$route.name !== 'Login'">
        <h3 @click="logOut" class ="arrow"><font-awesome-icon icon="sign-out-alt" /></h3>
      </span>
    <div align="center" class="message">{{message}}</div>

  </div>
</template>

<script>
import Auth from '@/Auth'
import store from "@/store"

export default {
  name: 'Header',
  data () {
    return {
      message:'〇〇システム',
      Auth:Auth,
    }
  },

  methods: {
    home: function () {
          this.$router.push('/home')
         },
     user: function(){
       return this.$store.state.user
     },
    logOut: function () {
          this.$router.push('/login')
         }
    },

  computed:{
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>


.message{
  clear: both;
}


.home{
    float: left;
  cursor: pointer;
}

.user{
    float: right;
}


.arrow{
    float: right;
    cursor: pointer;
}


</style>

```

＜template＞ の部分ででやっていることを少し捕捉すると、A01、B01、C01というように、各ユーザのトップページでは、「ホーム」ボタンを表示しないようにしています。また、ログインページにおいては、「ホーム」ボタンおよび「ログアウト」ボタンを表示しないようにしています。

もう一点。今回私のコードでは、ホームボタンにfont-awesomeのアイコンを使っていますが、これはなんでもかまいません。

```
<h3 @click="home" class="home"><font-awesome-icon icon="home" /></h3>
```
部分を

```
<h3 @click="home" class="home">Home</h3>
```

とすれば、アイコンではなくHomeという文字ボタンに変更できます。


はい。これでホームボタンを押した際、ユーザごとのトップページに遷移する、というのが実装できました。




#(おまけ)存在しないURLをたたいた時に、ログイン画面に遷移する。

おまけです。存在しないURLをたたいたとき、ログイン画面に遷移するというのを実装します。
今回は先に完成形のコードをお見せします。

```index.js

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/login',
      name: 'Login',
      component: Login,
      meta: {
        isPublic: true  
      }
    },
    {
      path: '/A01',
      name: 'A01',
      component: A01
    },
    {
      path: '/B01',
      name: 'B01',
      component: B01
    },
    {
      path: '/C01',
      name: 'C01',
      component: C01
    },
    {
      path: '*', 
      redirect: '/Login'
    }
  ]
})

```

この最後のところ

```
    {
      path: '*', 
      redirect: '/Login'
    }
```

で、存在しないURLをたたいたとき、/loginに遷移させる、というのを実現しています。