Vue.js サンプルコード


Vue.js のサンプルコードが意外に少ないなぁ、と感じたので、自分が理解できた範囲で「もっともわかりやすいと思うコード（主観）」を書いてみた。

自分の勉強を兼ねてます（失礼）

# これは誰のためのものですか？

[Web]が表示される仕組みが理解できていて、
[HTML] や [JavaScript] や [SVG] のコードがある程度読み書きができて、
[MVVM] というか [MVC] のおおよその概念もつかめていて、
[Webアプリ] の [UI] とかを仕事でガリガリ書いているんだけど、
そろそろ [AngularJS] とか [React.js] も使わないとなぁ、と思いながらも、複雑すぎて、習得に時間が掛かりそうだからスルーしたくて、
[Riot.js] から使ってみて、軽くていいけど、[SVG] との相性が最悪で、、、
[Vue.js] なら [SVG] との相性もいいとか学習コストが低いって聞いたのに本を買って読んでみてもちっとも頭に入ってこないので、
「もっと簡潔に的を射たサンプルコードはないのだろうか？」とググってみたひと向け。

[Web]:https://ja.wikipedia.org/wiki/WEB

[HTML]:https://ja.wikipedia.org/wiki/HyperText_Markup_Language

[JavaScript]:https://ja.wikipedia.org/wiki/JavaScript

[SVG]:https://ja.wikipedia.org/wiki/Scalable_Vector_Graphics

[Webアプリ]:https://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%A7%E3%83%96%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3

[UI]:https://ja.wikipedia.org/wiki/%E3%83%A6%E3%83%BC%E3%82%B6%E3%82%A4%E3%83%B3%E3%82%BF%E3%83%95%E3%82%A7%E3%83%BC%E3%82%B9

[MVC]:https://ja.wikipedia.org/wiki/Model_View_Controller

[MVVM]:https://ja.wikipedia.org/wiki/Model_View_ViewModel

[AngularJS]:https://angularjs.org/

[React.js]:https://reactjs.org/

[Riot.js]:https://riot.js.org/ja/

[Vue.js]:https://jp.vuejs.org/index.html

## Vue.js サンプルコード (1) v-model, v-on
まずは基本の new Vue(), v-model, v-on

```html
<html>
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.22/vue.min.js'></script><!-- 2019-01-25 https://cdnjs.com/libraries/vue -->
<body>

<div id="vue_example"></div>

<script>
var vue_example = new Vue({
  el: '#vue_example',

  template: `<div>
    <p>{{ message }}</p>
    <input v-model="message" />
    <button v-on:click="reverse()">Reverse</button>
    </div>`,

  data: {
    message: 'Hello Vue.js!',
  },

  methods: {
    reverse: function () {
      this.message = this.message.split('').reverse().join('')
    },
  },
})
</script>
</body>
</html>
```

<p class="codepen" data-height="300" data-theme-id="0" data-default-tab="result" data-user="yamazaki3104" data-slug-hash="MZNXoK" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="MZNXoK">
  <span>See the Pen <a href="https://codepen.io/yamazaki3104/pen/MZNXoK/">
  MZNXoK</a> by yamazaki.3104 (<a href="https://codepen.io/yamazaki3104">@yamazaki3104</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

なるべくシンプルに Vue.js の特徴が出るようなコードを書いてみたつもり。

### ポイント (1)

 - HTML には div しか書いてないところ。ほぼ JS で完結する。
 - v-model: input に入力する内容が message へリアルタイムで反映されるところ（すげー）
 - v-on: button をクリックして message を更新するとリアルタイムで反映されるところ（すげー）



## Vue.js サンプルコード (2) v-for
v-for を使って配列を表示

```html
<html>
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.22/vue.min.js'></script><!-- 2019-01-21 https://cdnjs.com/libraries/vue -->
<body>

<div id="vue_example"></div>

<script>
var vue_example = new Vue({
  el: '#vue_example',

  template: `<div>
    <ol><li v-for="(it,idx) in items">
    {{ it }} <button v-on:click="del_item( idx )"> x </button>
    </li></ol>
    <input v-model="item" />
    <button v-on:click="add_item()">Add Item</button>
    </div>`,

  data: {
    items: [ 'aaa', 'bbb', 'ccc', ],
    item: 'Hello Vue.js!',
  },

  methods: {
    add_item: function () { this.items.push( this.item ) },
    del_item: function ( _idx ) { this.items.splice( _idx, 1 ) }
  }
})

</script>
</body>
</html>
```

<p class="codepen" data-height="300" data-theme-id="0" data-default-tab="result" data-user="yamazaki3104" data-slug-hash="zygLpL" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="zygLpL">
  <span>See the Pen <a href="https://codepen.io/yamazaki3104/pen/zygLpL/">
  zygLpL</a> by yamazaki.3104 (<a href="https://codepen.io/yamazaki3104">@yamazaki3104</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

なんというか、いわゆる ToDoリストっぽいコードがこの行数で書けるのがすごい。

### ポイント (2)

 - items が配列でも、v-for を使って表示できるところ
 - v-on の click`"del_item( idx )"`は`"del_item( {{idx}} )`とはしない

## Vue.js サンプルコード (3) [fast-xml-parser]
HTML tag の表記を消してみた
[fast-xml-parser] を使って、JSON -> XML文字列 に変換することで、煩わしい HTML tag を書かずに、HTML を表示するチャレンジ。

[fast-xml-parser]:https://github.com/NaturalIntelligence/fast-xml-parser

```html
<html>
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.22/vue.min.js'></script><!-- 2019-01-21 https://cdnjs.com/libraries/vue -->
<script src='https://cdnjs.cloudflare.com/ajax/libs/fast-xml-parser/3.10.0/parser.min.js'></script><!-- 2019-01-21 https://cdnjs.com/libraries/fast-xml-parser -->

<div id="vue_example"></div>

<script>
var xml = new parser.j2xParser( {
  attributeNamePrefix: "_",
  textNodeName: "text_",
  ignoreAttributes: false,
  allowBooleanAttributes: true,
} )

var vue_example = new Vue({
  el: '#vue_example',

  template: xml.parse({
    div: {
      ol: {
        li: { "_v-for": "(it,idx) in items",
          text_: "{{ it }}",
          button: { "_v-on:click": "del_item( idx )",
            text_: " x ",
          },
        },
      },
      input: { "_v-model": "item", },
      button: { "_v-on:click": "add_item()",
        text_: "Add Item",
      },
    },
  }),

  data: {
    items: [ 'aaa', 'bbb', 'ccc', ],
    item: 'Hello Vue.js!'
  },

  methods: {
    add_item: function () { this.items.push( this.item ) },
    del_item: function ( _idx ) { this.items.splice( _idx, 1 ) }
  }
})

</script>
</body>
</html>
```
実行結果は、サンプル(2)とまったく同じ（はず）

<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="result" data-user="yamazaki3104" data-slug-hash="bzdmNq" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Vue.js example 3 (fast-xml-parser)">
  <span>See the Pen <a href="https://codepen.io/yamazaki3104/pen/bzdmNq/">
  Vue.js example 3 (fast-xml-parser)</a> by yamazaki.3104 (<a href="https://codepen.io/yamazaki3104">@yamazaki3104</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

### ポイント (3)

 - HTML tag を書かずに、HTML が表示できるのは（自分の中では）かなり画期的。


## Vue.js サンプルコード (4) components, $emit, $event, [SVG]
componentsを使って、[SVG] と連係してみた

```html
<html>
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.22/vue.min.js'></script><!-- 2019-01-21 https://cdnjs.com/libraries/vue -->
<body>

<div id="vue_example"></div>

<script>
var vue_example = new Vue({
  el: '#vue_example',

  components: {
    'component-A': {
      props: { title: String, idx: Number },
      template: `<svg height="60" width="200">
        <rect x="5" y="5" rx="20" ry="20" width="150" height="50" style="fill:red;stroke:black;stroke-width:5;opacity:0.6" />
        <text x="35" y="37" >{{ title }}</text>
        <circle v-on:click="$emit('component-A-del-item', idx )" cx="150" cy="16" r="16" fill="red" />
        </svg>`,
    },
  },

  template: `<div>
    <ol><li v-for='(it,idx) in items'>
    <component-A v-bind:title='it' v-bind:idx='idx'
      v-on:component-A-del-item='del_item( $event )'
    ></component-A>
    </li></ol>
    <input v-model='item' />
    <button v-on:click='add_item()'>Add Item</button>
    </div>`,

  data: {
    items: [ 'aaa', 'bbb', 'ccc', ],
    item: 'Hello Vue.js!'
  },

  methods: {
    add_item: function () { this.items.push( this.item ) },
    del_item: function ( _idx ) { this.items.splice( _idx, 1 ) }
  }
})

</script>
</body>
</html>
```

<p class="codepen" data-height="400" data-theme-id="0" data-default-tab="result" data-user="yamazaki3104" data-slug-hash="WPeEbE" style="height: 400px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Vue.js example 3">
  <span>See the Pen <a href="https://codepen.io/yamazaki3104/pen/WPeEbE/">
  Vue.js example 3</a> by yamazaki.3104 (<a href="https://codepen.io/yamazaki3104">@yamazaki3104</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

### ポイント (4)

 - component を使うとオリジナルのtagが作れる。Riot.js っぽい。
 - SVG との愛称もいい
 - $emit でイベントを伝播できる
 - $event で引数が受け取れる





## Vue.js サンプルコード (5) Vuetify
Vuetify のタグに置き換える

```html
<html>
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.22/vue.min.js'></script><!-- 2019-01-21 https://cdnjs.com/libraries/vue -->
<script src='https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.4.2/vuetify.min.js'></script>
<link  href='https://cdnjs.cloudflare.com/ajax/libs/vuetify/1.4.2/vuetify.min.css' rel='stylesheet'><!-- 2019-01-22 https://cdnjs.com/libraries/vuetify -->
<body>

<div id="vue_example"></div>

<script>
var vue_example = new Vue({
  el: '#vue_example',

  components: {
    'component-A': {
      props: { title: String, idx: Number },
      template: `<v-layout row>
          <v-flex grow pa-1>
            <v-card dark color="green darken-3">
              <v-card-text>{{ title }}</v-card-text>
            </v-card>
          </v-flex>
          <v-flex shrink pa-1>
            <v-btn large color="green darken-1" v-on:click="$emit('component-A-del-item', idx )"> Delete </v-btn>
          </v-flex>
        </v-layout>`,
    },
  },

  template: `<div>
    <component-A v-for='(it,idx) in items' v-bind:title='it' v-bind:idx='idx'
      v-on:component-A-del-item='del_item( $event )'
    ></component-A>
    <v-layout row>
      <v-flex grow pa-1>
        <v-text-field outline v-model='item'></v-text-field>
      </v-flex>
      <v-flex shrink pa-1>
        <v-btn large v-on:click='add_item()'>Add Item</v-btn>
      </v-flex>
    </v-layout>
    </div>`,

  data: {
    items: [ 'aaa', 'bbb', 'ccc', ],
    item: 'Hello Vue.js!'
  },

  methods: {
    add_item: function () { this.items.push( this.item ) },
    del_item: function ( _idx ) { this.items.splice( _idx, 1 ) }
  }
})
</script>
</body>
</html>
```

<p class="codepen" data-height="600" data-theme-id="0" data-default-tab="result" data-user="yamazaki3104" data-slug-hash="PVoGwZ" style="height: 600px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Vue.js example 4 (Vuetify)">
  <span>See the Pen <a href="https://codepen.io/yamazaki3104/pen/PVoGwZ/">
  Vue.js example 4 (Vuetify)</a> by yamazaki.3104 (<a href="https://codepen.io/yamazaki3104">@yamazaki3104</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>

### ポイント (5)

 - Vuetify のタグに置き換えただけで、UIがカラフルになる！（すげー）


## Vue.js サンプルコード (6) watch, [Chart.js]
[Chart.js] と連係

[Chart.js]:https://www.chartjs.org/

```html
<html>
<script src='https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.min.js'></script><!-- 2019-01-25 https://cdnjs.com/libraries/Chart.js -->
<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.22/vue.min.js'></script><!-- 2019-01-22 https://cdnjs.com/libraries/vue -->

<body>

<canvas id='chart' height='200'></canvas><br>
<div id='vue_example'></div>

<script>
var vue_example = new Vue( {
  el: '#vue_example',

  template: `<div>
    <ol><li v-for="(it,idx) in labels">
    <button v-on:click="del_item( idx )"> x </button> {{ it }} : {{ values[idx] }} 
    </li></ol>
    <input v-model="label">
    <button v-on:click="add_item()">Add Item</button>
    </div>`,

  data: {
    labels: [ 'Red', 'Blue', 'Green' ],
    values: [ 33, 55, 11, ],
    label: 'Hello Vue.js!',
  },

  methods: {
    add_item: function () {
      this.labels.push( this.label )
      this.values.push( Math.floor( Math.random() * 100 ) )
    },
    del_item: function ( _idx ) {
      this.labels.splice( _idx, 1 )
      this.values.splice( _idx, 1 )
    },
  },

  watch: {
    labels: function () {
      chart.data.labels = this.labels
      chart.data.datasets[0].data = this.values
      chart.update()
    },
  },
} )

var chart = new Chart( document.getElementById('chart').getContext('2d'), {
  type: 'bar',
  data: {
    labels: vue_example.labels,
    datasets: [ { label: 'example', data: vue_example.values, }, ],
  },
} )
</script>
</body>
</html>
```

<p class="codepen" data-height="697" data-theme-id="0" data-default-tab="html,result" data-user="yamazaki3104" data-slug-hash="wRVRNx" style="height: 697px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Vue.js example 6 (Chart.js)">
  <span>See the Pen <a href="https://codepen.io/yamazaki3104/pen/wRVRNx/">
  Vue.js example 6 (Chart.js)</a> by yamazaki.3104 (<a href="https://codepen.io/yamazaki3104">@yamazaki3104</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

### ポイント (6)

 - watch でデータが変化した時のイベントが取れる（すげー）
 - Chart.js は chart.update() で勝手にアニメーションするのがすごい


## 参考
いまのところこのサイトが一番わかりやすいと思っている（本家だしね）
https://jp.vuejs.org/v2/guide/

まだまだ、奥は深そうなので勉強を続ける所存。

（Qiita ＆ Codepen 初投稿記念 2019/01）