Vue.jsでFizzBuzzを書いてみる

2017年のコード書き初めは今まで使ったことないものにしようと思い、
Reacよりもとっつきやすいと噂のVue.jsを使ってFizzBuzzを書いてみました。

# 成果物
|▼デモ|
|:--|
|![vue-fizzbuzz_demo.gif](https://qiita-image-store.s3.amazonaws.com/0/55219/73ab1171-5ab6-eb1b-d8d1-3df02c1a50b5.gif)|

# セットアップ

[公式ドキュメント](https://jp.vuejs.org/v2/guide/installation.html)に従って `vue-cli` を入れます。
vue-cli をインストールしたらボイラープレートを使用してプロジェクト作成します
また状態管理のために [vuex](https://github.com/vuejs/vuex) もインストールしておきます

```
# vue-cli をインストール
$ npm install --global vue-cli
# "webpack" ボイラープレートを使用した新しいプロジェクトを作成する
$ vue init webpack vue-fizzbuzz
# 依存関係をインストールしてgo!
$ cd vue-fizzbuzz
$ npm install
# vuexをインストール
$ npm install --save vuex
$ npm run dev
```

あとは不要なファイル、コードを削除して、実装を進めていきます。

# コード

`src` ディレクトリ以下は以下のような構成になりました

```
src
├── App.vue
├── components
│   ├── Buttons.vue
│   └── FizzBuzz.vue
├── main.js
└── store.js
```

```js:main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import store from './store'

/* eslint-disable no-new */
new Vue({
  el: '#app',
  store,
  template: '<App/>',
  components: { App }
})
```

```html:App.vue

<template>
  <div id="app">
    <fizz-buzz></fizz-buzz>
    <buttons></buttons>
  </div>
</template>

<script>
import FizzBuzz from './components/FizzBuzz'
import Buttons from './components/Buttons'

export default {
  name: 'app',
  components: {
    FizzBuzz,
    Buttons
  }
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
```

```html:components/FizzBuzz.vue
<template>
  <div>
    <div v-if="fizzbuzz">{{ fizzbuzz }}</div>
    <div v-else>{{ $store.state.count }}</div>
  </div>
</template>

<script>
import { mapGetters } from 'vuex'

export default {
  computed: mapGetters([
    'fizzbuzz'
  ])
}
</script>
```

```html:components/Buttons.vue
<template>
  <div class="buttons">
    <button @click="increment" >+</button>
    <button @click="decrement" >-</button>
  </div>
</template>

<script>
import {mapActions} from 'vuex'

export default {
  methods: mapActions([
    'increment',
    'decrement'
  ])
}
</script>
```

```js:store.js
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const state = {
  count: 1
}

const mutations = {
  increment (state) {
    state.count++
  },
  decrement (state) {
    state.count--
  }
}

const actions = {
  increment: ({commit}) => commit('increment'),
  decrement: ({commit}) => commit('decrement')
}

const getters = {
  fizzbuzz: state => {
    let message = ''
    if (state.count % 3 === 0) message += 'Fizz'
    if (state.count % 5 === 0) message += 'Buzz'

    return message
  }
}

export default new Vuex.Store({
  state,
  getters,
  actions,
  mutations
})

```

# 感想

jsxのようにjsにhtmlを埋め込んでいくのではなく
vueファイルに `template` `script` `style` を書いていくので
コードがわかりやすく良さげですね。
`v-if` `@click` などのAPIもいい感じに書けるので書いてて気持ちがいいです。

riot.js と似ている感じですが、riot.jsとくらべて
`vue-cli` `vuex` などのツール・ライブラリがあるので
かなりとっつきやすい印象を受けました。


2017年は vue.js を使って何かelectronアプリを作成してみたいですね〜