【Vue.js】vuex + vue-router でヘッダータイトルを共通化する方法

# この記事の内容

スマホ向けwebアプリやスマホアプリなんかでよくあるヘッダーのタイトルが切り替わる方法が簡単に実装できるようになります。

以下のようなイメージです。（アイコンが同じなのでわかりにくいかもしれませんがご了承ください）

ホームview表示時
![0001.JPG](https://qiita-image-store.s3.amazonaws.com/0/183354/bc731deb-505b-004c-c200-af58acfe225f.jpeg)

アバウトview表示時
![0002.JPG](https://qiita-image-store.s3.amazonaws.com/0/183354/257712ba-4f6e-66d5-98ec-3c563b8b0b15.jpeg)


# 実装

## vue-routerでafter フックを登録する

vue ui等で作った場合 routerが変数になっていないので変数に代入する点に注意してください。

初期時

```javascript:router.js

export default = new Router({
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
    },
  // ----省略----
  ]
})
```

変更後

```javascript:router.js

const router  = new Router({
 routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
    },
  // ----省略----
  ]
})
export default router;

```

この状態で afterEachを登録します。

```javascript:router.js

export default router;

router.afterEach((to,from) =>{
  console.log('呼ばれたよ!')
})
```

実行してみましょう npmの場合 npm run serve
ページ切り替えでconsoleに「呼ばれたよ!」と表示されましたでしょうか？

## routerにmetaプロパティを追加する


先ほど作ったrouterに対して、metaプロパティを追加してあげましょう。
metaプロパティの中は下の例のように任意でいくつでも設定できます。

```javascript:router.js

const router  = new Router({
 routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
      meta:{
        title:'ほーむ',
        hoge:'ほげほげ',
      },
    },
  // ----省略----
  ]
})
export default router;

```


先ほど作ったrouterで取得できるか確認しましょう。

```javascript:router.js

router.afterEach((to,from) =>{
    console.log(to.meta.title);
    console.log(to.meta.hoge);
})
```

こちらも成功しましたでしょうか？

## storeにstateを追加する。

正直storeの作り方は人それぞれなので参考程度に見てください。
私の場合はstore.js１つで管理するやり方をとっています。他にmoduleをファイルごとに分けて管理する方法もありますが、個人的に可読性が良く無いなぁと思ったので１つでまとめています。

```javascript:store.js
const store = new Vuex.Store({
  modules: {
    common: {
      namespaced: true,
      state: {
        pageTitle: 'Home',
      },
      actions: {
        changePage({ commit }, title) {
          commit('cahgePageTitle', title);
        },
      },
      mutations: {
        cahgePageTitle(state, title) {
          const st = state;
          st.pageTitle = title;
        },
      },
      getters: {
        pageTitle(state) {
          const st = state;
          return st.pageTitle;
        },
      },
    },
// ----以下省略----
  }
})

export default store;
```

次にこちらで設定したstateをviewで取得します。
Header.vueなんかを作ってもよかったんですが、今回はわかりやすくApp.vueで作ります。

```html:App.vue

    <div id="header">
      {{pageTitle}}
    </div>

<script>
import { mapGetters } from 'vuex';

export default {
  data() {
    return {};
  },
  computed: {
    ...mapGetters({
      pageTitle:'common/pageTitle',
    }),
  },
};
</script>

```

mapGetters を利用してstateからpageTitleを取得してきています。
これでstoreの値をviewに持ってくることができました。

## vue-routerからstoreにアクセスする。

通常 this.$storeのようにやったとしても vue-routerからstoreにアクセスすることはできません。
しかし、やり方は簡単で Evanさん の言う通り store.jsをimportすればいいだけです。

https://github.com/vuejs/vuex-router-sync/issues/26#issuecomment-254030655

ついでにafterEachの中身も変えてあげましょう。
今回の設計上storeの値を書き換えるのはmutationsなのでそれにアクセスしているactionのchangePageにdispatchしてあげます。


```javascript:router.js
import store from './store';

// ----省略----

router.afterEach((to,from) =>{
  if (to.meta && to.meta.title) {
    store.dispatch('common/changePage', to.meta.title)
  }
})

```

以上で終了です。
実際に動きましたでしょうか？

# まとめ
遷移時の処理はそれぞれに書かないで、router.js一か所でまとめるようにしましょう。
では良いVue.jsライフを