Vue CLIでVue Router + Vuetifyの環境構築と設定

の個人用メモです。ダークモードの切り替えと、ページ遷移時のメタタグとスムーススクロールの設定までが目標です。

#開発環境

* node.js : v12.18.3
* vue-cli : 4.5.10
* yarn : 1.22.10

#プロジェクトの作成
Vue CLI UIが大変便利なのでこちらを使用します。

```
$ vue ui
```

ブラウザが立ち上がるのでGUIからプロジェクトを作成。バージョンは2.xを選択。
今回はVue Routerを使用するので、忘れずにチェックしておきましょう。

#プラグイン等のインストール
同じくGUIからプラグインのインストールを行います。今回はVuetifyをインストールします。Axiosを使用する場合はサイドメニューの｢依存｣からインストールします。
ここで一旦、serveしてプロジェクトが立ち上がるか確認しておきましょう。見慣れた画面と出会えたらここまではおｋです。

#ファイルの追加、修正
プロジェクトディレクトリ直下に以下の2ファイルを追加。

```javascript:.eslintrc.js
module.exports = {
  root: true,
  env: {
    node: true,
  },
  extends: ['plugin:vue/essential', 'eslint:recommended', '@vue/prettier'],
  parserOptions: {
    parser: 'babel-eslint',
  },
  rules: {
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'prettier/prettier': [
      'error',
      {
        //お好みで設定
        singleQuote: true,
        trailingComma: 'es5',
        arrowParens: 'always',
        endOfLine: 'auto',
      },
    ],
  },
};
```

```json:jsconfig.json
{
  "include": ["./src/**/*"],
  "compilerOptions": {
    "module": "es2015",
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}
```

以下の4ファイルを修正。

```javascript:src/router/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
import goTo from 'vuetify/lib/services/goto';

Vue.use(VueRouter);

export default new VueRouter({
  //mode: 'history', //historyモードで使用する場合はコメントアウト
  base: process.env.BASE_URL,
  scrollBehavior: (to, from, savedPosition) => {
    let scrollTo = 0;

    if (to.hash) {
      scrollTo = to.hash;
    } else if (savedPosition) {
      scrollTo = savedPosition.y;
    }

    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(goTo(scrollTo));
      }, 0);
    });
  },
  routes: [
    {
      path: '/',
      name: 'home',
      component: Home,
      meta: { title: 'home | my project', desc: 'This is a home page' }, //ページ毎のメタタグの設定
    },
    {
      path: '/about',
      name: 'about',
      component: About,
      meta: { title: 'about | my project', desc: 'This is an about page' },
    },
  ],
});

```

```javascript:src/plugins/vuetify.js
import Vue from 'vue';
import Vuetify from 'vuetify/lib/framework';

Vue.use(Vuetify);

export default new Vuetify({
  theme: {
    dark: false, //ダークモードの初期設定
    themes: {
      light: {
        primary: '#1976D2',
        secondary: '#424242',
        accent: '#82B1FF',
        error: '#FF5252',
        info: '#2196F3',
        success: '#4CAF50',
        warning: '#FFC107',
        background: '#f5f5f5', //ダークモード切り替え時の背景色の設定
      },
      dark: {
        primary: '#1976D2',
        secondary: '#424242',
        accent: '#82B1FF',
        error: '#FF5252',
        info: '#2196F3',
        success: '#4CAF50',
        warning: '#FFC107',
        background: '#3e3e3e',
      },
    },
  },
  //ブレイクポイントの設定が必要であれば
  breakpoint: {
    mobileBreakpoint: 767.98,
  },
});
```

```vuejs:App.vue
<template>
  <v-app :style="{ background: $vuetify.theme.themes[theme].background }">
    <v-app-bar app>
      <v-tabs>
        <v-tab to="./">home</v-tab>
        <v-tab to="./about">about</v-tab>
      </v-tabs>
      <v-spacer></v-spacer>
      <v-switch v-model="$vuetify.theme.dark"></v-switch>
    </v-app-bar>
    <v-main>
      <router-view />
    </v-main>
  </v-app>
</template>

<script>
export default {
  name: 'App',
  mounted() {
    const routeInstance = this.$route;
    this.createTitleDesc(routeInstance);
  },
  computed: {
    theme() {
      return this.$vuetify.theme.dark ? 'dark' : 'light';
    },
  },
  watch: {
    $route(routeInstance) {
      this.createTitleDesc(routeInstance);
    },
  },
  methods: {
    createTitleDesc(routeInstance) {
      //title設定
      if (routeInstance.meta.title) {
        const setTitle = routeInstance.meta.title;
        document.title = setTitle;
      } else {
        document.title = 'title is not set';
      }
      //description設定
      if (routeInstance.meta.desc) {
        const setDesc = routeInstance.meta.desc;
        document
          .querySelector("meta[name='description']")
          .setAttribute('content', setDesc);
      } else {
        document
          .querySelector("meta[name='description']")
          .setAttribute('content', 'description is not set');
      }
    },
  },
};
</script>
```

```html:index.html
<!--追加-->
<meta name="description">
```

ダークモードの切り替え、ページ遷移時のメタタグの切り替えとスムーススクロールができていれば完了です。

以下はAxiosを使用する場合の設定です(コンポーネント毎に個別でインポートする場合は不要)。
コンポーネント内にて``this.$axios``で使用します。

```javascript:main.js
//追加
import axios from 'axios';

Vue.prototype.$axios = axios;
```


#最後に
以下の記事を参考にさせていただきました。感謝！

[Vue.jsをVSCodeで書く時はVeturを入れてjsconfig.jsonを書こう](https://qiita.com/nyallpo/items/c50909926e465fabdb55)
[Vue.js の開発にESLint + Prettier + Vetur を導入してみた](https://matazoukun.hatenablog.com/entry/2021/02/05/054814)
[【Vue.js】Vue CLIで作成したページのtitleとdescriptionを変更する方法](https://qiita.com/shizen-shin/items/1fc2d1f5b4add2c0ed2c)
[Vuetifyのテーマ(スタイル)変更について](https://qiita.com/yusuke-ka/items/80dd90307e2b5debf5b8)