Vue.js勉強したのでエンジニアポートフォリオサイト作ってみた

## はじめに
Vue.jsの勉強がてらポートフォリオサイト作って公開しました。せっかく作ったので忘れないように技術的な内容をまとめようと思います。

Vue.jsやアニメーションなど効果的には使えていないと思うので、温かい目で見てもらえると幸いです。

## Web開発の経験について
5,6年前にとある企業の社内報サイトと人材管理Webシステムの開発に携わり、下記のWeb系の技術経験が1~2年ほどあります。（5年以上経つのでかなり忘れていました。。。）

HTML, CSS, AngularJS, SpringBoot, MySQLなど

## モチベーション
* たまたまWebデザインの最新トレンド記事を読んで、自分のデザイン感覚がアップデートできていないことに気づいた。最低限の感覚はアップデートしたい
* せっかくなのでフロントエンドの人気のフレームワークに触れてみたい
* フロントエンドの忘れた知識を取り戻したい
* 今まで技術的な発信してこなかったので何か発信したい

## 作成したポートフォリオサイトについて
作成したサイトはこちら。[Ike's Portfolio](https://portfolio-yi.web.app/)

### 技術要素
* Vue.js
 * 単一ファイルコンポーネント
 * Vue Router / SPA
 * Element UI
* デザイン
 * パララックス
 * アニメーション
 * マウスカーソルの動きに合わせて動く背景（パララックスの一部かも？）
* その他
 * Firebase Hosting

### 画面構成
#### TOP
* アニメーション
* マウスカーソルの動きに合わせて動く背景
![スクリーンショット](https://user-images.githubusercontent.com/25924137/116689193-bd6ab980-a9f2-11eb-97ec-4befbd4791c1.gif)

#### Profile
![スクリーンショット 2021-04-30 18.52.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65742/e6fc9aef-af9f-43fa-a718-164bdc208f3e.png)

#### Skill Set
* アニメーション（スライドイン）
* パララックス
![Ike-s-Portfolio_skill](https://user-images.githubusercontent.com/25924137/116695063-058dda00-a9fb-11eb-8271-ef6829892a4b.gif)

#### Works
* アニメーション（フェイドイン）
* element ui （プログレスバー）
![Ike-s-Portfolio_work](https://user-images.githubusercontent.com/25924137/116695115-15a5b980-a9fb-11eb-9e99-ec6d87dd4383.gif)

#### Contact
![Ike-s-Portfolio_contact](https://user-images.githubusercontent.com/25924137/116695551-bc8a5580-a9fb-11eb-9970-68a1a4ba0f85.png)

## 実装
### 全体
各セクションを単一ファイルコンポーネントで作成し、大枠のvueから呼び出すような構成にしました。

```vue:App.vue
<template>
  <div id="app">
    <Header />
    <!-- ルーティング時の表示領域を準備 -->
    <router-view/> <!-- Home.vueが呼ばれる -->
    <Footer />
  </div>
</template>
```

```vue:Home.vue
<template>
  <div class="home">
    <Splash />
    <Profile />
    <Skill />
    <Works />
    <Contact />
  </div>
</template>
```

### アニメーション（フェードイン、スライドイン）
アニメーションは複数ファイルで利用できるようコンポーネント化しました。「slot」を利用してアニメーションさせたい要素を別ファイルから差し込めるようにしています。
参考記事：[[Vue.js]スクロールでコンテンツがフェードインする実装](https://qiita.com/RyoTa0222/items/cba9c1cebc6fda927837)

また、アニメーション処理については、まずスクロール位置を管理するため「addEventListener()」を用いてスクロールイベントをリスナー登録します。特定の位置までスクロールしたら変数`visible`を`true`にし、アニメーションを指定するcssのclassが付与されるようにしています。


下記はフェードインのソースコードですが、スライドインも同様に作成しています。

```vue:FadeInComponent.vue
<template>
  <div ref="fade" :class="{fadein: visible, hidden: !visible}">
    <slot v-show="visible"></slot>
  </div>
</template>

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

<style scoped>
.hidden {
  opacity: 0;
}

.fadein {
  animation: fadeIn 1s;
  opacity: 1;
}

@keyframes fadeIn {
  0% {
    opacity: 0;
    transform: translateY(50px);
  }
  100% {
    opacity: 1;
    transform: translateX(0px);
  }
}
</style>
```

アニメーションさせたい要素を上記コンポーネントで挟み込むことで動作するようにしています。

```vue:Skill.vue
    <FadeIncomponent>
      <h1 class="title">Skill Set</h1>
    </FadeIncomponent>
```

### パララックス
わかりにくいですが、Skill Setの背景にパララックスを適用しています。
![Ike-s-Portfolio_skill](https://user-images.githubusercontent.com/25924137/116695063-058dda00-a9fb-11eb-8271-ef6829892a4b.gif)

パララックスは`directives`を使い、HTMLタグに指定できるようにしました。
scroll量に合わせて背景画像のポジションを`background-position-y`で変化させることで実現しています。

参考記事：https://note.com/rottenmarron/n/nb7a23b1483ca

```vue:Skill.vue（directives箇所を抜粋）
<script>
~~~~~~~~~~~~ 省略 ~~~~~~~~~~~~~~
  directives: {
    parallax: {
      inserted (el, binding) {
        el.setAttribute( // 初期状態のスタイル
          'style',
            `
              background-position: center top;
              background-size: initial;
              backgroung-repeat: no-repeat;
              background-position-y: ${window.scrollY / binding.value.denominator}px;
            `
        )
        window.addEventListener('scroll', () => {
          el.setAttribute( // スクロール量に応じて動的に変化するスタイル
            'style',
            `
              background-position: center center;
              background-size: initial;
              backgroung-repeat: no-repeat;
              background-position-y: ${window.scrollY / binding.value.denominator + 300}px;
            `
          )
        })
      }
    }
  },
~~~~~~~~~~~~ 省略 ~~~~~~~~~~~~~~
</script>
```

下記のようにHTMLタグにdirectivesを指定することで要素にパララックス効果を適用しています。

```vue:Skill.vue（directiveの指定）
  <div id="skill" class="bg-blar" :class="{safari: safari}" v-parallax="{
        height: '100vh',
        denominator: 1.8
    }">
```

### マウスカーソルの動きに合わせて動く背景
[parallax.jsライブラリ](http://matthew.wagerfield.com/parallax/)を使用しました。

視差効果を付与したい要素に対して`new Parallax`でオプションを指定するだけでマウスカーソルの位置に合わせて要素が移動します。

```vue:Splash.vue（HTML）
    <div id="parallax">
      <div data-depth="0.2">
        <h1 class="title">
          Ike's Portfolio
        </h1>
        <span>Full Stack Engineer</span>
      </div>
    </div>
```
```vue:Splash.vue（script）
<script>
export default {
~~~~~~~~~~~~ 省略 ~~~~~~~~~~~~~~
  mounted () {
    this.$nextTick(function () {
      var layer = document.getElementById('parallax')
      const parallax = new Parallax(layer, {
        scalarX: 10.0, // X軸の移動速度と範囲を増減
        scalarY: 10.0, // Y軸の移動速度と範囲を増減
        frictionX: 0.1, // X軸のレイヤーの速度。0.00〜1.00の範囲内で指定可能
        frictionY: 0.1, // Y軸のレイヤーの速度。0.00〜1.00の範囲内で指定可能
      })
    })
    window.addEventListener('scroll', this.onScroll)
  },
~~~~~~~~~~~~ 省略 ~~~~~~~~~~~~~~
</script>
```

### プログレスバー
[Element UI](https://element.eleme.io/#/en-US/component/progress#progress)ライブラリを利用しました。
Elementライブラリ導入後に、`<el-progress>`タグを利用することで簡単にプログレスバーを描画することができます。

![プログレスバー](https://user-images.githubusercontent.com/25924137/116888468-7dac0800-ac66-11eb-8151-e5082d87e48e.png)

```vue:Skill.vue
<div class="progress-wrapper">
  <span>Swift / Objective-C</span>
  <el-progress :percentage="80"></el-progress>
</div>
```

## Web公開
### Firebase Hosting
ホスティングにはFirebase Hostingを利用しました。以下の理由で選定しました。

* 将来的に他のFirebaseサービス（Cloud Functions for Firebaseなど）と組み合わせる可能性あり
* サーバ費用、ドメイン費用が無料
* CDNエッジサーバのSSDキャッシュに保存されるので、コンテンツを高速に配信できる

導入方法は[Firebase Hosting公式サイト](https://firebase.google.com/docs/hosting?hl=ja)記載の導入手順を実行すればお手軽に導入できます。

## 今後の展望
* 内容が薄いので厚くしたい。特に個人開発の欄を増やしたい
* 検索しても出て来ないのでSEO対策する
* CSSを整理したい
* ブログ作って発信する量を増やしたい
* 色々効果的に利用できていないので、UI/UXデザインを学びたい
* 移り変わりが早いので定期的に新しいトレンドを学ぶ


最後まで閲覧いただきありがとうございました。もしコメントがあればいただけますと嬉しいです。