VuetifyとVue-CLIで爆速でポートフォリオページ作った

SenKです。筆者はインターン以前はVue.jsでの開発経験がありませんでしたが、勢いでポートフォリオページを作成することができました。作成にはVue CLIとVuetifyを利用したのですが、手軽に作成できたのでレポートしようと思います。PC版のTOPです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390513/57f0e60d-14b5-7879-2b7c-a27c3a62fb04.png)

[ポートフォリオ](https://senk8.github.io/)
[リポジトリ](https://github.com/senk8/senk8.github.io)


#環境構築

環境の構築方法について述べます。nodejsをインストールしていることを前提にしています。

##かかった日数と筆者のスキル

合計３０時間ほど。日数としては7日間で、だいたいがググっている時間だった。筆者はフロントエンドの経験がインターンで一週間やったVueと過去のインターンでやったHTML/CSS程度しかない。JavaScriptはAjaxくらいまでの知識はある。

##バージョン情報

| 対象 |　バージョン |
|:-:|:-:|
|OS| macOS Catalina 10.15.6  |
|nodejs  |  14.8.0 |
|Vue CLI   |  4.5.4 |
|Vuetify   | 2.2.11 |


##Vue-CLIのインストール

Vue.jsをコマンドラインで開発するためのパッケージです。簡単にSPAを作成できます。早速インストールしましょう。
まず、vue-cliをインストールします

```bash
$ npm install -g vue-cli
```

次にプロジェクトを作ります。今回のポートフォリオはこのプロジェクト内で作成することになります。ここではプロジェクト名をprojectとして作成しました。

```bash
$ vue create project

Vue CLI v4.5.4
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Vuex
? Use history mode for router? (Requires proper server setup for index fallback
in production) Yes
? Where do you prefer placing config for Babel, ESLint, etc.? In package.json
? Save this as a preset for future projects? No
```

そして以下のコマンドを実行します。

```bash
$ cd project
$ npm run serve
```


そしたらターミナルのここに書かれているURLにアクセスしましょう。

![スクリーンショット 2020-09-03 15.02.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390513/491816b8-1eb2-f0ee-5db5-ce620af2b9fd.png)


こちらが表示されていれば準備OKです。

![スクリーンショット2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390513/885ab210-95c1-7459-f6eb-cadde11081d9.png)


##Vuetifyのインストール
[Vuetify](https://vuetifyjs.com/ja/)はVue.jsのフレームワークのひとつで簡単にUIが作成できます。
例えば、`<v-btn>...</v-btn>`と書けばそれだけでカッコいいボタンが作れます。今後登場するv-...のようなタグは全てVuetifyの物です。早速導入しましょう。

```bash
$ vue add vuetify
```

なんか聞かれますが、yesとdefaultを選んでおいてください。インストールが終わったら`npm run serve`をして、またターミナルに表示されているURLにアクセスしてください。こちらが表示されていればOKです。

![スクリーンショット1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390513/b6c052d1-a4a5-1a30-0132-98c01b756ee4.png)



##VueScrollToのインストール

詳しくは後に記述しますが、Vueを使ってイージングスクロールするためのパッケージです。簡単にインストールできます。

```bash
$ npm install vue-scrollto
```

とりあえず今はこれで終わりにして実装に取り掛かりましょう。

#実装のハイライト
実装で力をいれてポイントについて紹介します。このセクションでは`project/src`ディレクトリを`@`と略記します。

##実装するもの

今回はTop(ページトップ)、AboutMe（自己紹介）、SkillSet(持っているスキル)、Activities(活動記録)は最低限必要だと思ったので、それらを作成することにしました。

Topの画像はCSSを貼るだけでグラデーションを作ってくれる[uiGradients](https://uigradients.com/#EasyMed)を利用しました。

##イージングスクロール

ページ内コンテンツへの移動を楽にするためにページ内リンクを作り、それをイージングスクロールにしたいと思います。イージングスクロールっていうのはカッコよくなめらかに移動してくれるアニメーション付きのスクロールです。

すでにVueScrollToのインストールができていると思います。プロジェクトで使えるようにしていきます。２つのファイルに下記の書き加えを行ってください。

```javascript:@/components/vue-scrollto.js
//このファイルはプロジェクト作成時点では存在しない。

import Vue from 'vue';
import VueScrollTo from 'vue-scrollto'

Vue.use(VueScrollTo,{
    duration:1000,//早すぎないように遅くする
    offset: -60,//オフセットで遷移先の要素がヘッダーに隠れるのを対策
    easing:"ease-out"//ease-outが直感的かと思い採用
})

export default new Vue({
});

```

```javascript:@/main.js
...
import vuescrollto from './plugins/vue-scrollto'; //これ

Vue.config.productionTip = false
new Vue({
  ...
  vuescrollto, //これ
  render: h => h(App)
}).$mount('#app')

```

VueScrollToの導入が完了しました。それでは基本的な使い方をみていきます。筆者のこの部分の実装は[@/components/Header.vue(https://github.com/senk8/senk8.github.io/blob/master/portfolio/src/components/Header.vue)に実装があります。

今回はvuetifyの[Tabs](https://vuetifyjs.com/ja/components/tabs/)を使います。


```vuejs:@/components/Header.vue
...
<v-tab v-for="info in tabInfo" :key="info.to_id" v-scroll-to="info.to_id" :href="info.url">
 {{ info.subtitle }}
 <v-icon>{{ info.icon }}</v-icon>
</v-tab>
...
```

この部分では

![スクリーンショット 2020-09-03 16.04.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390513/58986429-4e6a-af6f-a332-ce1225e87b52.png)

を実装するためにv-forでデータを並べています。ここでVueScrollToに関係あるのは`v-scroll-to="info.to_id" :href="info.url"`の部分です。この部分をidがaboutmeの要素までスクロールするように書くと、`v-scroll-to="'#aboutme'" :href="#aboutme"`になります。

VueScrollToはタグの属性に`v-scroll-to="遷移先のID"`を指定することでスクロールを行うことができます。`href`を指定することで遷移と同時にurlも変わります。遷移先は例えば下記のように書きます。

```
<div id="aboutme">
...
</div>
```

移動先の実装は[@/views/AboutMe.vue](https://github.com/senk8/senk8.github.io/blob/master/portfolio/src/views/AboutMe.vue)にあります。


##フェードイン

ページをスクロールしたとき、スクロールと同時にページの要素が浮き出るようにしたいと思いました。そのためにVueの`transition`を使います。以下のファイルを作ってください。

```vuejs:@/components/FadeIn.vue
<template>
  <div>
    <transition name="fade">
        <slot v-if="show"></slot>
    </transition>
  </div>
</template>

<script>
export default {
  name: 'Fade',
  data() {
    return{
      show:false
    };
  },
  methods:{
    handleScroll() {
      if (!this.show) {
        var top = this.$el.getBoundingClientRect().top;
        this.show = top < window.innerHeight + 100;
      } 
    }
  },
  created() {
    window.addEventListener('scroll', this.handleScroll);
  },
  destroyed() {
    window.removeEventListener('scroll', this.handleScroll);
  }
}
</script>
```

このコードは[この記事](https://qiita.com/RyoTa0222/items/cba9c1cebc6fda927837)を参考に書きました。

これを書き加えたらこのファイルを他のファイルからimportし、アニメーションをつけたい要素を囲います。以下の例では`@/components/AboutMe.vue`でアニメーションをつけています。


 ```vuejs:@/components/AboutMe.vue
<template>
　　...
    <FadeIn>
    
<!-- アニメーションをつけたい要素を記述-->

    </FadeIn>
    ...
</template>


<script>
...
import FadeIn from "@/components/FadeIn"//これ

export default {
  ...
  components:{
    ...
    FadeIn//これ
  },
  ...
}
</script>

<style scoped>
...
</style>

```

その後、CSSでアニメーションをつけて完成です。[筆者のポートフォリオ](https://senk8.github.io/)を見ると、どんなアニメーションがつくのかわかります。

 ```vuejs:@/components/AboutMe.vue
<template>
    ...
</template>

<script>
...
</script>

<style scoped>

.fade-enter-active,
.fade-leave-active {
  transition: opacity 2s
}

.fade-enter,
.fade-leave-to {
  opacity: 0
}
</style>

```

##レスポンシブルデザイン

スマホでの閲覧に対応したく、レスポンシブルデザインにしたいと思いました。スマホ版のデザインでは[Tabs](https://vuetifyjs.com/ja/components/tabs/)が[Navigation Drawers](https://vuetifyjs.com/ja/components/navigation-drawers/)に切り替わるようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390513/b0273dce-3de2-58f3-7878-90b480673b67.png)

![スクリーンショット 2020-09-03 16.32.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390513/04046bd1-3d22-475c-7c37-a91478b44f00.png)

これをどのように実現しているのかといえば、[Display](https://vuetifyjs.com/ja/components/display/)という機能を使っています。例えば以下のように指定すると実現できます。


```vuejs:@/components/Header.vue
<template>
    ...
        <v-app-bar-nav-icon class="d-flex d-sm-none"/>
        <v-tabs 
        light-green
        icons-and-text
        centered
        >
          <div class="d-none d-sm-flex">
          ...
          </div>
        </v-tabs>
    ...
</template>
...
```

`class="d-flex d-sm-none"`を指定すると、スマホのときだけ表示し、`class="d-none d-sm-flex"`を指定すると、PCのときだけ表示するようになります。

これを[ブレークポイント](https://vuetifyjs.com/ja/customization/breakpoints/)といいます。この機能を使うことで、画面の大きさに応じて要素の大きさ、表示非表示、文字サイズ、寄せる方向などを切り替えられます。詳しくは公式ドキュメントの以下を参照してください。

- [Grid](https://vuetifyjs.com/ja/components/grids/)
- [Display](https://vuetifyjs.com/ja/components/display/)
- [flex](https://vuetifyjs.com/ja/components/flex/)
- [Text](https://vuetifyjs.com/ja/components/text/)

#デプロイ

実装が終わったので早速github-pagesで公開しましょう。

##ローカルでやること

まずvue.config.jsに下記の内容を書き加えてください。

```vuejs:project/vue.config.js
module.exports = {
  publicPath:"./",
  outputDir:"docs",
　...
}
```

次に`project`ディレクトリで下記のコマンドを実行します。

```bash
$ npm run build
```

`project/docs`というフォルダができると思います。これをマスターブランチでのルートディレクトリに移動させてください。（自分のディレクトリ構造は https://github.com/senk8/senk8.github.io のようになりました。）

##リモートでやること

ここまでが終了したら、githubにプッシュします。なお、README.mdがマスターブランチのルートにあるとバグるので、README.mdは`.github`ディレクトリを作ってその中に退避してください。

最後にポートフォリオ用のgithubのリポジトリ→settingからgithub-pagesのSourceの設定を`/docs`にします。

![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390513/ee274bdd-dc0e-2bb5-120a-0e2de0a0eae5.png)

これでhttps://<ユーザー名>.github.io/にアクセスすれば表示されているはずです！お疲れ様でした！


#まとめ

Vue.jsの強力さを思い知りました。ポートフォリオを爆速で作って、困った時のホームページにしてしまいましょう！