Vue ( vue-router,  vuex, vue-material, json-vue-er, MongoDB ) を使って Boilerplate

前回の記事
http://qiita.com/Satachito/items/7c393513bf42ea3d1ebd
で、vue を単一の HTML で見てきました。

今回は vue-cli を使用して、アプリのボイラーブレートらしく仕立ててみます。
バックエンドは MongoDB のビルトイン REST インターフェースを使ってみます。
http://qiita.com/Satachito/items/ec7b8cad2bf88b4c21fb

最終形はここにおいてあります。
https://github.com/Satachito/vue-sample


# テンプレートのロード
vue-cli でアプリを作っていきます。

```
$ vue init webpack-simple bp
```

いくつか質問されます。

? Project name *bp*
? Project description *A Vue.js project*
? Author *XXXXXX*
? Use sass? *No*

上のように答えたとして、進めていきます。

bp の下に移動して、

```
npm i
npm run dev
```
として、動作確認しましょう。

bp の下の以下の3つのファイルをとりあえず使っていきます。（他にもありますが、とりあえず無視してください。）

```
index.html
src/main.js
config/index.js
```

# vue のみ

```src/main.js
import Vue from 'vue'

new Vue({
  el: '#app'
, template: `<div>APP</div>`
})
```

ブラウザに APP と表示されます。

# vue + vue-router
```
npm i vue-router --save
```
とモジュールをインストール。

```src/main.js
import Vue from 'vue'

import Router from 'vue-router'
Vue.use(Router)

new Vue({
  el: '#app'
, router: new Router({
    routes:
    [ { path: '/sub', component: { template: '<div>SUB</div>' } }
    , { path: '/', component: { template: '<div>HOME</div>' } }
    ]
  })
, template: `
    <div>
      <router-link to='/'>Goto HOME</router-link>
      <router-link to='/sub'>Goto SUB</router-link>
      <router-view/>
    </div>
  `
})
```

# vuex に行く前にお化粧

vue-material を使って上の vue + vue-router をアプリっぽくしてみます。

## index.html で Material 用のフォントとアイコンを読むようにします。

```index.html
<!DOCTYPE html>
<meta charset="utf-8">
<title></title>

<link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:300,400,500,700,400italic">
<link rel="stylesheet" href="//fonts.googleapis.com/icon?family=Material+Icons">

<div id="app"></div>
<script src="/dist/build.js"></script>
```

## vue-material を npm でインストールします。

```
npm i vue-material --save
```

で、こんな感じ。

```src/main.js
import Vue from 'vue'

import Router from 'vue-router'
Vue.use(Router)

import 'vue-material/dist/vue-material.css'
import VueMaterial from 'vue-material'
Vue.use( VueMaterial )

new Vue({
  el: '#app'
, router: new Router({
    routes:
    [ { path: '/sub', component: { template: '<div>SUB</div>' } }
    , { path: '/', component: { template: '<div>HOME</div>' } }
    ]
  })
, template: `
    <div>
      <md-toolbar>
        <md-button class="md-icon-button" @click.native="$refs.sideNav.open()">
          <md-icon>menu</md-icon>
        </md-button>
        <h2 class="md-title" style="flex: 1">Default</h2>
        <md-button class="md-icon-button">
          <md-icon>favorite</md-icon>
        </md-button>
      </md-toolbar>
      <md-sidenav class="md-left" ref="sideNav">
        <md-list>
          <md-list-item @click.native="$refs.sideNav.close()"><router-link to='/'>Goto HOME</router-link></md-list-item>
          <md-list-item @click.native="$refs.sideNav.close()"><router-link to='/sub'>Goto SUB</router-link></md-list-item>
        </md-list>
      </md-sidenav>
      <router-view/>
    </div>
  `
})
```
![SS.png](https://qiita-image-store.s3.amazonaws.com/0/73493/c1872b01-ec31-d6c4-6330-27c7dbe93d0a.png)
ハンバーガーボタンを押すと：
![SS2.png](https://qiita-image-store.s3.amazonaws.com/0/73493/f70807b6-801b-d972-4b82-8d81c2f5c124.png)


# テストデータにつなぐ

MongoDB のビルトイン REST インターフェースにつないでみます。
http://qiita.com/Satachito/items/ec7b8cad2bf88b4c21fb

今回アクセスしたい URL は localhost:28017/test/restaurants/ ですが、
直接 fetch すると same origin policy にひっかかってしまうため、
proxy を設定しなくてはなりません。
config/index.js の proxyTable を以下のように編集して、
/test 以下が localhost:28017 にフォワードされるようにします。

```config/index.js
proxyTable: { '/test': { target: 'http://localhost:28017', changeOrigin: true } },
```

で、こんな感じ。

```src/main.js
import Vue from 'vue'

import Router from 'vue-router'
Vue.use(Router)

import 'vue-material/dist/vue-material.css'
import VueMaterial from 'vue-material'
Vue.use( VueMaterial )

new Vue({
  el: '#app'
, data() { return { m: { rows: [] } } }
, router: new Router({
    routes:
    [ { path: '/detail/:idx', component: { template: '<h1>{{ $route.params.idx }}</h1>' } }
    , { path: '/', component: { template: '<div>HOME</div>' } }
    ]
  })
, created() {
    fetch( '/test/restaurants/?limit=10' ).then(
      p => p.json()
    ).then(
      p => this.m = p
    ).catch(
      err => alert( err )
    )
  }
, template: `
    <div>
      <md-toolbar>
        <md-button class="md-icon-button" @click.native="$refs.sideNav.open()">
          <md-icon>menu</md-icon>
        </md-button>
        <h2 class="md-title" style="flex: 1">Default</h2>
        <md-button class="md-icon-button">
          <md-icon>favorite</md-icon>
        </md-button>
      </md-toolbar>
      <md-sidenav class="md-left" ref="sideNav">
        <md-list>
          <md-list-item v-for="( w, i ) in m.rows" :key="i">
            <router-link :to="'/detail/' + i" @click.native="$refs.sideNav.close()">{{ i + ':' +  w.name }}</router-link>
          </md-list-item>
        </md-list>
      </md-sidenav>
      <router-view/>
    </div>
  `
})
```






# vue + vue-router + vuex

veux をインストール

```
npm i vuex --save
```

フェッチした JSON を表示するために、json-vue-er を npm でインストールします。

```
npm i json-vue-er --save
```

で、こんな感じ。

```src/main.js
import Vue from 'vue'

import Router from 'vue-router'
Vue.use(Router)

import Vuex from 'vuex'
Vue.use(Vuex)

import 'vue-material/dist/vue-material.css'
import VueMaterial from 'vue-material'
Vue.use( VueMaterial )

import JsonVueEr from "json-vue-er/JsonVueEr"

let
Detail = {
  components: { JsonVueEr }
, template: `<json-vue-er :json="$store.state.json.rows[ $route.params.idx ]"></json-vue-er>`
}

let
Home = {
  components: { JsonVueEr }
, template: `<json-vue-er :json="$store.state.json"></json-vue-er>`
}

new Vue({
  el: '#app'
, store: new Vuex.Store({
    state: { json: { rows: [] } }
  , mutations: {
      json: ( state, payload ) => state.json = payload.json
    }
  })
, router: new Router({
    routes:
    [ { path: '/detail/:idx', component: Detail }
    , { path: '/', component: Home }
    ]
  })
, created() {
    fetch( '/test/restaurants/?limit=10' ).then(
      p => p.json()
    ).then(
      p => this.$store.commit( 'json', { json: p } )
    ).catch(
      err => alert( err )
    )
  }
, template: `
    <div>
      <md-toolbar>
        <md-button class="md-icon-button" @click.native="$refs.sideNav.open()">
          <md-icon>menu</md-icon>
        </md-button>
        <h2 class="md-title" style="flex: 1">Default</h2>
        <md-button class="md-icon-button">
          <md-icon>favorite</md-icon>
        </md-button>
      </md-toolbar>
      <md-sidenav class="md-left" ref="sideNav">
        <md-list>
          <md-list-item v-for="( w, i ) in $store.state.json.rows" :key="i">
            <router-link :to="'/detail/' + i" @click.native="$refs.sideNav.close()">{{ i + ':' +  w.name }}</router-link>
          </md-list-item>
        </md-list>
      </md-sidenav>
      <router-view/>
    </div>
  `
})
```
![SS3.png](https://qiita-image-store.s3.amazonaws.com/0/73493/5a756f1d-9d62-936e-db4b-da1781b6200d.png)

![SS4.png](https://qiita-image-store.s3.amazonaws.com/0/73493/5f1652df-39bc-d6d9-9caa-fc3284bb94c4.png)

# 出来上がったものはここにおいてあります。

https://github.com/Satachito/vue-sample