Vue.jsはじめました（ビギナー向けまとめ）

食べログフロントエンドチームの@nakiaです。

元請けのSIerで3年半ほどシステム屋さんをやってましたが、もっと自分でコード書けるようになりたい！と一念発起しまして、ちょうど1年前に食べログにやってきました:tada:
優秀なメンバーに囲まれ、学びの多い毎日を送っています:hatching_chick:


今日のAdventCalendarは、フロントエンド初心者の私が0からVue.jsを勉強した学習記録です！
公式ガイドの他に「[基礎から学ぶVue.js](https://cr-vue.mio3io.com/)」（書籍）を参考にしています。

初心者向けなので、より実践的な内容をお求めの方はぜひ[@empitsu88](https://qiita.com/empitsu88) さんの「[Nuxt.js+TypeScriptのアプリケーションのためのコーディングガイドライン](https://qiita.com/empitsu88/items/f02513fa669a2ce0cd28)」をご覧ください:information_desk_person:

#Vue.jsの基本
## Vue.jsとは
比較的新しい**JavaScriptのフレームワーク**です。以下のような特徴があります。

- 導入のしやすさ・学習コストの低さ
    - バンドル・プリコンパイルしなくても動く
    - Hello World！を表示するまでが簡単
- スケールの柔軟性
    - ページ内の１機能〜SPAの大きなプロダクトまで対応可能
- 日本語ドキュメントの充実
    - 本体以外のドキュメントも日本語充実！（ビギナー的にこれは非常にありがたい）

機能単体でサクッと導入できる感じは、フレームワークというよりライブラリに近い使用感です。
jQuery的な手軽さがあります。

## Vue.jsのキーコンセプト：データ駆動
Vue.jsの基本となる考え方は、**データ駆動**です。

- 従来のJSの考え方
  - DOM構造に合わせてデータを加工し描画する
- Vue.jsの考え方
  - データの変更に合わせてDOMを構築・更新する（データバインディング）

簡単なサンプルを紹介します。
適当なフォルダに以下のファイルを作成して、ブラウザで開いてみてください。


```html

<!DOCTYPE html>
<html>
<body>
<div id="app">
  <h1>{{ message }}</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.13"></script>
<script>
  var app = new Vue({
    el: '#app',
    data: {
      message: 'Hello Vue.js!'
    }
  })
</script>
</body>
</html>
```

dataに定義されたmessageを更新すると、`{{ message }}`の中身が動的に更新されます。

上記のようなテキストバインディングの他に、

- イベントを利用する
- フォーム入力した内容と表示を同期する
- 条件によって表示を出し分ける
- 簡易なアニメーションをつける

などなど、様々な便利機能が用意されています。
詳しい説明は[Vue.js公式ガイド](https://jp.vuejs.org/v2/guide/)をご覧ください。

## Nuxt.jsとは

**Vue.jsをベースにしたフレームワーク**です。
上で書いたように、Vue.jsは機能単位で簡単に導入でき、柔軟に拡張できるというメリットがあります。
一方で、きちんとルールを決めて運用していかないとコードがカオスになりやすいという欠点もあります。
（これはVue.jsに限った話ではなく、従来のフロントエンド開発の課題でもあります）

この欠点を補ってくれるのが、Nuxt.jsのもたらす「規約」です。
Ruby on RailsがRuby開発のベストプラクティスをルールとして定めているように、Nuxt.jsはVue開発のベストプラクティスを定めています。
Nuxt.jsの規約に従うことで、設計や実装方法について議論するコストを最小限に抑えつつ、一定の納得感が得られるアーキテクチャと統一的な記述を担保できます。

もちろん、Nuxt.jsは現代のフロントエンド開発に必要な機能についても一通り備えています。

- SSR（Server Side Rendering）
- webpack、モジュールの最適化（ビルドプロセスの隠蔽）
- Vue本体,Vue拡張機能との連携

こちらも日本語で[公式ガイド](https://ja.nuxtjs.org/guide/)が公開されてますので、詳細はそちらをご確認ください。


#Vue.jsの周辺技術

Vue + Nuxtで開発するときにお世話になる周辺技術を紹介します！

## 状態管理したい：Vuex
[Vuex](https://vuex.vuejs.org/ja/)はデータとその状態を一元管理するための拡張ライブラリです。

コンポーネントベースの開発（※）では、基本的に$emitやpropsを使ってコンポーネント間でデータのやりとりをしますが
アプリケーションの規模が大きくなると、データ管理の処理もそれだけ煩雑になります。

Vuexでデータを管理すると、コンポーネントの構造に関わらず
アプリケーション全体で同じデータを同期的に共有できるようになります。

※コンポーネント開発はそれだけで１冊本が書けるぐらい壮大なテーマなので、今回は説明を割愛します。
[Vueにおけるコンポーネント](https://jp.vuejs.org/v2/guide/#%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AB%E3%82%88%E3%82%8B%E6%A7%8B%E6%88%90)については公式にちょっとだけ説明があるので、気になる人は見てみてください。

Vuexストアはこんな感じで書きます。

```js
// モジュールシステムを利用しているときはあらかじめ Vue.use(Vuex) を呼び出していることを確認しておいてください

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  }
})
```

これで `store.state` でストアオブジェクトの状態を参照、 `store.commit`で状態の変更を行うことができるようになります。

## ルーティングしたい：Vue Router
[Vue Router](https://router.vuejs.org/ja/guide/#html)は、Single Page Application（SPA）を構築するための拡張ライブラリです。
各コンポーネントとURLを紐付けてくれます。

### SPAとは
単一のWebページの中で複数の要素（コンポーネント）を置き換えることで画面遷移を実現する設計のことです。
必要な要素だけを読み込むので描画が素早いのが特徴です。
遷移時にアニメーションをつけることでいわゆる「イマドキなWebページ」を作ることができます。

###Nuxt.jsにおけるルーティングの仕組み
Nuxt.jsでは**\<nuxt-link>**というコンポーネントを使用してルーティングを実現します。

```html
<template>
  <nuxt-link to="/">Home page</nuxt-link>
</template>
```


以下のように、決められたディレクトリ構造に従ってファイルを配置するだけで自動的にURLを生成してくれるので、とっても便利です！

■ディレクトリ構造

```
pages/
--| user/
-----| index.vue
-----| one.vue
--| index.vue
```

■生成されるroutes

```config

router: {
  routes: [
    {
      name: 'index',
      path: '/',
      component: 'pages/index.vue'
    },
    {
      name: 'user',
      path: '/user',
      component: 'pages/user/index.vue'
    },
    {
      name: 'user-one',
      path: '/user/one',
      component: 'pages/user/one.vue'
    }
  ]
}
```

具体的な設定方法は[公式のサンプル](https://ja.nuxtjs.org/guide/routing/)をご覧ください。


## バリデーションしたい：Vee Validate

[Vee Validate](https://logaretm.github.io/vee-validate/overview.html#getting-started)は複雑なバリデーションを実装する場合に便利なVueライブラリのひとつです。
（[こちらのページ](https://jp.vuejs.org/v2/cookbook/form-validation.html#%E4%BB%A3%E6%9B%BF%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)で紹介されていますが、Vue.jsが公式で提供しているものではなく、日本語版のガイドがまだありません…）

対象のコンポーネントにValidationProviderをimportすると、バリデーションが利用できるようになります。

```js
import { ValidationProvider } from 'vee-validate';

Vue.component('ValidationProvider', ValidationProvider);
// ...
```

対象のフォーム全体を**\<ValidationProvider>**で囲み、rulesプロパティにバリデーションルールを設定します。
ruleに違反した場合、ValidationProviderから受け取ったerrorsを描画します。

```html
<ValidationProvider rules="positive" v-slot="{ errors }">
  <input v-model="value" type="text">
  <span>{{ errors[0] }}</span>
</ValidationProvider>
```

バリデーションルールは以下のように関数で定義することができます。

```js
import { extend } from 'vee-validate';

extend('positive', value => {
  return value >= 0;
});
```

ちなみに、submit直前のエラー表示など、フォーム全体を監視したい場合は**\<ValidationObserver>**でフォームを囲みます。



## HTTP通信したい（axiosを使いたい）
### axiosとは
HTTP通信を簡単に行うことができる、PromiseベースのJSライブラリです。
主にAPIからデータを取得して表示したいときに使用します。

```js
// GET通信
axios.get('http://localhost:7000/user')

    // thenで成功した場合の処理をかける
    .then(response => {
        console.log('status:', response.status); // 200
        console.log('body:', response.data);     // response body.

    // catchでエラー時の挙動を定義する
    }).catch(err => {
        console.log('err:', err);
    });
```

[Vue.jsでaxiosを使う書き方](https://jp.vuejs.org/v2/cookbook/using-axios-to-consume-apis.html)は公式をご覧ください。


### Nuxt.js用のaxios module 
コンポーネントを初期化する前に非同期の処理を行いたいケースを想定し、Nuxt.jsは[asyncData](
https://ja.nuxtjs.org/guide/async-data/)というメソッドを用意しています。
>asyncData は ページ コンポーネントがローディングされる前に常に呼び出されます。サーバーサイドでは 1回だけ（Nuxt アプリへの最初のリクエスト）呼び出され、クライアントサイドではページ遷移をするたびに呼び出されます。

とのことです。

```js
export default {
  async asyncData ({ params }) {
    const { data } = await axios.get(`https://my-api/posts/${params.id}`)
    return { title: data.title }
  }
}
```
asyncDataの結果を受けてコンポーネントの描画を更新できます。

```html
<template>
  <h1>{{ title }}</h1>
</template>
```

## TypeScriptで書きたい：vue-class-component/vue-property-decorator

TypeScriptと使用すると、型定義によってより堅牢にJSを書けるようになります。
VueアプリケーションをTypeScriptで実装する場合、以下のようなプラグインを利用することで可読性を高めることができます。

**vue-class-component**：Vueを継承したClassとしてコンポーネントを宣言できるようになります。
**vue-property-decorator**：`@Props`などデコレーターを使って宣言できるようになります。

具体的な書き方については、以下の記事が大変参考になりました！
https://qiita.com/ryo2132/items/4d43209ea89ad1297426
https://qiita.com/hatakoya/items/8d9968d07748d20825f8

#まとめ

いかがでしたか？実は、記念すべきQiita初投稿でした…！
質問・コメントはお手柔らかにお願いします:pray:


明日は[@k-sekido](https://qiita.com/k-sekido)さんの「システム開発で納得感を持って進めるために考えていること」です！
お楽しみに〜:christmas_tree: