Vue.js の基本的な機能を使ったサンプルを書く

## 概要

- Mustache 構文、条件付きレンダリング、メソッド、算出プロパティ、フォーム入力バインディング、リストレンダリング、コンポーネントの機能を使ったサンプルコードを示す
- 環境: Vue.js 2.6.11

## Mustache 構文で Hello World

- 画面に Hello, world! と表示するサンプルコード

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello, world!</title>
</head>
<body>

<div id="app">
  <!-- Mustache 構文で message プロパティを表示 -->
  <p>{{ message }}</p>
</div>

<!-- デバッグに便利な Vue.js の開発バージョンを使う -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>
// Vue インスタンスを生成
new Vue({

  // Vue インスタンスが管理する DOM 要素
  el: '#app',

  // プロパティ
  data: {
    message: 'Hello, world!'
  }
})
</script>

</body>
</html>
```

[テンプレート構文 — Vue\.js](https://jp.vuejs.org/v2/guide/syntax.html)

> データバインディングのもっとも基本的な形は、”Mustache” 構文(二重中括弧)を利用したテキスト展開です:

## 条件付きレンダリング、メソッド、算出プロパティ

- 「カウントアップ」ボタンを押すとカウント数が1増える
- カウント数を表示する
- 3の倍数のときはカウント数ではなく「あほー」と表示する

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Counter</title>
</head>
<body>

<div id="myCounterDiv">

  <!-- DOM イベントをトリガーに設定 -->
  <button v-on:click="myCountUp">カウントアップ</button>

  <!-- データバインディング -->
  <!-- v-bind で title 属性にセット -->
  <!-- Mustache 構文で要素内に表示 -->
  <p v-bind:title="myMessage">カウンター: {{ myMessage }}</p>

  <!-- 条件付き描画 (Conditional Rendering) -->
  <p v-if="myCounter % 6 == 0">6の倍数ですね</p>
  <p v-else-if="myCounter % 3 == 0">3の倍数ですね</p>
  <p v-else-if="myCounter % 2 == 0">2の倍数ですね</p>
  <p v-else>2の倍数でも3の倍数でもないですね</p>
</div>

<!-- サイズと速度が最適化された Vue.js の本番バージョンを使う -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

<script>
// Vue インスタンスを生成
var vm = new Vue({

  // Vue インスタンスが管理する DOM 要素
  el: '#myCounterDiv',

  // プロパティ
  data: {
    myCounter: 0
  },

  // created フック
  // インスタンスが作成された後に同期的に呼ばれる
  created: function() {
    this.myCounter = 1
  },

  // メソッド
  methods: {
    myCountUp: function (event) {
      this.myCounter++
    }
  },

  // 算出プロパティ (computed properties)
  computed: {
    myMessage: function () {
      if (this.myCounter % 3 == 0) {
        return "あほー" // 3の倍数のときに返す値
      } else {
        return this.myCounter
      }
    }
  }
})

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

[イベントハンドリング — Vue\.js](https://jp.vuejs.org/v2/guide/events.html)

> v-on ディレクティブを使うことで、DOM イベントの購読、イベント発火時の JavaScript の実行が可能になります。

[API — Vue\.js](https://jp.vuejs.org/v2/api/#v-bind)

> v-bind

> 1つ以上の属性またはコンポーネントのプロパティと式を動的に束縛します。

[条件付きレンダリング — Vue\.js](https://jp.vuejs.org/v2/guide/conditional.html)

> v-if ディレクティブは、ブロックを条件に応じて描画したい場合に使用されます。ブロックは、ディレクティブの式が真を返す場合のみ描画されます。

[Vue インスタンス — Vue\.js](https://jp.vuejs.org/v2/guide/instance.html)

> Vue インスタンスが作成されると、自身の data オブジェクトの全てのプロパティをリアクティブシステムに追加します。これらのプロパティの値を変更すると、ビューが”反応”し、新しい値に一致するように更新します。

[Vue インスタンス — Vue\.js](https://jp.vuejs.org/v2/guide/instance.html)

> 各 Vue インスタンスは、生成時に一連の初期化を行います。例えば、データの監視のセットアップやテンプレートのコンパイル、DOM へのインスタンスのマウント、データが変化したときの DOM の更新などがあります。その初期化の過程で、特定の段階でユーザー自身のコードを追加する、いくつかの ライフサイクルフック(lifecycle hooks) と呼ばれる関数を実行します。
> 
> 例えば、created フックはインスタンスが生成された後にコードを実行したいときに使われます。

[算出プロパティとウォッチャ — Vue\.js](https://jp.vuejs.org/v2/guide/computed.html)

> 算出プロパティの代わりに、同じような関数をメソッドとして定義することも可能です。最終的には、2つのアプローチは完全に同じ結果になります。しかしながら、算出プロパティはリアクティブな依存関係にもとづきキャッシュされるという違いがあります。

## フォーム入力バインディング、リストレンダリング

- フォームに入力したテキストをリストに追加
- リストを表示

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>List</title>
</head>
<body>

<div id="myListDiv">

  <!-- フォーム入力バインディング -->
  <input v-model="myItem" placeholder="アイテム名">

  <!-- DOM イベントをトリガーに設定 -->
  <button v-on:click="myAddItem">{{ myItem }} を追加</button>

  <!-- 配列を表示 -->
  <ul>
    <li v-for="item in myItemList">
      {{ item.name }}
    </li>
  </ul>

</div>

<!-- Vue.js のバージョン 2.6.11 を使う -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>

<script>
var vm = new Vue({

  // Vue インスタンスが管理する DOM 要素
  el: '#myListDiv',

  // データ
  data: {
    myItem: '',
    myItemList: [
      { name: 'やくそう' },
      { name: 'どくけーしー' }
    ]
  },

  // メソッド
  methods: {
    myAddItem: function() {
      if (this.myItem !== '') {
        this.myItemList.push({name: this.myItem})
        this.myItem = ''
      }
    }
  },
})

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

[フォーム入力バインディング — Vue\.js](https://jp.vuejs.org/v2/guide/forms.html)

> form の input 要素 や textarea 要素、 select 要素に双方向 (two-way) データバインディングを作成するには、v-model ディレクティブを使用することができます。

[リストレンダリング — Vue\.js](https://jp.vuejs.org/v2/guide/list.html)

> 配列に基づいて、アイテムのリストを描画するために、v-for ディレクティブを使用することができます。v-for ディレクティブは item in items の形式で特別な構文を要求し、items はソースデータの配列で、item は配列要素がその上で反復されているエイリアスです:

## コンポーネント

- それぞれ別のカウント値を持ったカウンター
- ボタンを押すとカウント数が1増える

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Counters by Components</title>
</head>
<body>

<div id="components-demo">
  <!-- それぞれが別のインスタンスになるため、それぞれ別の count プロパティを保持する -->
  <button-counter></button-counter>
  <button-counter></button-counter>
  <button-counter></button-counter>
</div>

<!-- デバッグに便利な Vue.js の開発バージョンを使う -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>

// button-counter という新しいコンポーネントを定義
// コンポーネントは再利用可能な Vue インスタンス
Vue.component('button-counter', {

  // コンポーネントの data オプションは関数でなければならない
  data: function () {
    return {
      count: 0
    }
  },

  // Vue インスタンスに対して使用するテンプレート文字列
  // クリックするとカウントアップ count++
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

new Vue({
  // Vue インスタンスが管理する DOM 要素
  el: '#components-demo',
})

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

[コンポーネントの基本 — Vue\.js](https://jp.vuejs.org/v2/guide/components.html)

> コンポーネントは再利用可能な Vue インスタンスなので、data、computed、watch、methods、ライフサイクルフックなどの new Vue と同じオプションを受け入れます。唯一の例外は el のようなルート固有のオプションです。

## コンポーネントのプロパティ

- 表示情報のデータをコンポーネントに渡す

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Blog Posts by Components</title>
</head>
<body>

<div id="components-demo">
  <!-- 定義した blog-post コンポーネントを表示 -->
  <!-- v-bind:key で仮想 DOM 処理ヒント用にユニークなキーである myPost.id を指定 -->
  <!-- blog-post の post 属性に値 myPost を渡す -->
  <blog-post
    v-for="myPost in myPostList"
    v-bind:key="myPost.id"
    v-bind:post="myPost"
  ></blog-post>
</div>

<!-- デバッグに便利な Vue.js の開発バージョンを使う -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<script>

// blog-post という新しいコンポーネントを定義
// コンポーネントは再利用可能な Vue インスタンス
Vue.component('blog-post', {

  // データを受け取るためのプロパティ
  props: ['post'],

  // HTML 描画用テンプレート
  // Mustache 構文でタイトルを出力
  // v-html で HTML をそのまま出力
  template: `
    <div class="blog-post">
      <h3>{{ post.title }}</h3>
      <div v-html="post.content"></div>
    </div>
  `
})

new Vue({
  el: '#components-demo',
  data: {
    myPostList: [
      { id: 1, title: 'たいとる1', content: '<p>なかみ1</p>' },
      { id: 2, title: 'たいとる2', content: '<p>なかみ2</p>' },
      { id: 3, title: '>_<;', content: '<p>こうですか！？ わかりません＞＜</p>' }
    ]
  }
})

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

[コンポーネントの基本 — Vue\.js](https://jp.vuejs.org/v2/guide/components.html)

> プロパティはコンポーネントに登録できるカスタム属性です。値がプロパティ属性に渡されると、そのコンポーネントインスタンスのプロパティになります。

## 参考資料

- [はじめに — Vue\.js](https://jp.vuejs.org/v2/guide/)
- [API — Vue\.js](https://jp.vuejs.org/v2/api/)