Re:ゼロから始めるVue.js生活

# 前章

[ゼロから始めるVue.js生活](https://qiita.com/hashimotologly/items/416f741c9f6f7c266837)


# v-onでイベント処理を使いこなす

`v-on:click="メソッド名"`とすることで任意のメソッドをクリック時に発動できる

```html
<!-- HTML -->
<div id="hoge">
  <button v-on:click="hogeck">ホゲるボタン</button>
  <p>{{ message}}</p>
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: '#hoge',
    data: {
      message: 'まだホゲってない'
    },
    methods: {
      hogeck: function(){
        this.message = 'ほげぇぇぇぇぇぇぇぇ'
      }
    },
  })
</script>
<!-- Vue -->
```

[![Image from Gyazo](https://i.gyazo.com/0e49222f933865f7d8d77cee78078e57.gif)](https://gyazo.com/0e49222f933865f7d8d77cee78078e57)

また、`v-on:click`は`@click`と省略できる

```html
<button v-on:click="hogeck">ホゲるボタン</button>
<button @click="hogeck">ホゲるボタン</button>
```

### 引数について

#### 引数の渡し方

```html
<!-- HTML -->
<div id="hoge">
  <button @click="hogeck('ほげええええええ')">ホゲるボタン</button>
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: '#hoge',
    methods: {
      hogeck: function(message){
        alert(message)　// ホゲるボタン
      }
    },
  })
</script>
<!-- Vue -->

```



#### イベントオブジェクト
イベントオブジェクトとは、その名の通りイベントに関する情報を管理しているオブジェクトになる
`function(arg_event)`としてやることで（引数名はなんでも良い。暫定的に`arg_event`としている)、`arg_event`にイベントオブジェクトが格納される。


```html
<!-- HTML -->
<div id="hoge">
  <button @click="hogeck">ホゲるボタン</button>
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: '#hoge',
    methods: {
      hogeck: function(arg_event){
        alert(arg_event.target.textContent)　// ホゲるボタン
      }
    },
  })
</script>
<!-- Vue -->
```

#### イベントオブジェクトと引数を同時に受け取る場合

メソッドの第二引数に`$event`を入れてやることで取得可能。
$event以外の名前では動作しないので注意

```html

<!-- HTML -->
<div id="hoge">
  <button @click="hogeck('ほげええええええ',$event)">ホゲるボタン</button>
</div>
<!-- HTML -->


<!-- Vue -->
<script>
  var app = new Vue({
    el: '#hoge',
    methods: {
      hogeck: function(message1,arg_event){
        alert(message1) // ほげええええええ
        alert(arg_event.target.textContent) // ホゲるボタン
      }
    },
  })
</script>
<!-- Vue -->
```

## `computed`と`method`の動作の違いを使いこなす

`computed`と`method`の動作が似通っていて、混乱される方がいるかもぢれない(私もそうです)。
大きな違いとしては以下の通り

- method
    - 画面の再描画時に必ず実行される

- computed
    - 呼び出されたプロパティに変化があった場合に実行される(プロパティに変化がない場合は実行されない)


### 呼び出されたプロパティに変化があった場合
具体的にみてみよう

```html
<!-- HTML -->
<div id="hoge">
  <button @click="onclick()">ほげボタン</button> <!-- ほげボタン -->
  <div>ホゲった数: {{count}}</div>
  <p>hoge_method: {{hoge_method()}}</p>
  <p>hoge_computed: {{hoge_computed}}</p>
</div>
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: '#hoge',
    data: {
      count: 1,
    },
    methods: {
      onclick: function () {
        this.count++;
      },
      hoge_method: function () {
        return Math.random()
      }
    },
    computed: {
      hoge_computed: function () {
        console.log(this.count)
        return Math.random()
      }
    },
  });
</script>
<!-- Vue -->
```

[![Image from Gyazo](https://i.gyazo.com/5cc6ba9502ce7aec594d551ec6997485.gif)](https://gyazo.com/5cc6ba9502ce7aec594d551ec6997485)

ご覧のように`ホゲった数`が変化する度に`hoge_method`と`hoge_computed`が実行されていることがわかる。

コード中のこの部分に注目してほしい

```javascript

computed: {
      hoge_computed: function () {
        console.log(this.count)
```

`hoge_computed`内で`this.count`を呼び出しており、この`this.count`はボタンを押す度に変化する。
''呼び出されたプロパティ(count)に変化があった''ので、`hoge_computed`も実行されたわけだ。


### 呼び出されたプロパティに変化がない場合

`console.log(this.count)`を消して実行してみる

```html
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>


<!-- HTML -->
<div id="hoge">
  <button @click="onclick()">ほげボタン</button> <!-- ほげボタン -->
  <div>ホゲった数: {{count}}</div>
  <p>hoge_method: {{hoge_method()}}</p>
  <p>hoge_computed: {{hoge_computed}}</p>
</div>
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: '#hoge',
    data: {
      count: 1,
    },
    methods: {
      onclick: function () {
        this.count++;
      },
      hoge_method: function () {
        return Math.random()
      }
    },
    computed: {
      hoge_computed: function () {
        return Math.random()
      }
    },
  });
</script>
<!-- Vue -->
```

[![Image from Gyazo](https://i.gyazo.com/636f4cf1349de1e648522b16c801c24e.gif)](https://gyazo.com/636f4cf1349de1e648522b16c801c24e)

`count`自体はクリックの度に変化しているが、
`hoge_computed`では`count`を呼び出していないので、実行されず、画面上の表示も変わらない。


##v-modelを使いこなす

```html
<!-- HTML -->
<div id="hoge">
  <input type="text" v-model="hoge" ><br>
  <p>{{hoge}}</p>
</div>
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: '#hoge',
    data: {
      hoge: "ほげ？"
    }
  });
</script>
<!-- Vue -->
```
[![Image from Gyazo](https://i.gyazo.com/20e0235a20eb25a5f4a26b60f79da37d.gif)](https://gyazo.com/20e0235a20eb25a5f4a26b60f79da37d)
ご覧のようにフォームの入力に応じて、下の表示(hogeプロパティ)が動的に変化していることがわかる

流れとしては


- フォームの入力値(value)に変化がある度にイベント処理を行って、変化した値をhogeプロパティに反映する ... v-on
- フォームの入力値(value)とhogeプロパティを結びつける ... v-bind

の２ステップとなっている。

上記の流れに倣い、先ほど例示したコードを書き直してみる

```html
<!-- HTML -->
<div id="hoge">
  <input type="text" v-bind:value="hoge" v-on:input="hogeck"><br>
  <p>{{hoge}}</p>
</div>
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: '#hoge',
    data: {
      hoge: "ほげ？"
    },
    methods: {
      hogeck: function (event) {
        this.hoge = event.target.value
      }
    }
  });
</script>
<!-- Vue -->
```

###v-modelのv-bindとv-onの対象は入力方式に依存する

v-modelが常に`v-bind:value`、`v-on:input`から成るわけではない。先ほどのはあくまでも、テキスト入力フォームでの一例にすぎない

例えばこう、

|フォーム |v-bind  |v-on  |
|---|---|---|
|テキスト、複数行テキスト |value  |input  |
|チェックボックス、ラジオボタン|checked |change|
|プルダウンなどの選択リスト | value | change |


## templateタグを使いこなす

v-forを使って子要素を複数回表示したい場合、

```html
  <div v-for="hoge in hoges" v-bind:key="hoge.id">
    <h1>{{hoge.name}}</h1>
  </div>
```
のように親要素内にv-forを入れてやることで出力ができるが、そもそもこの`div`要素を出力したいないケースがある。
その時は、templateタグを使うと良い

```html
<!-- HTML -->
<div id="hoge">
  <template v-for="hoge in hoges">
    <h1>{{hoge.name}}</h1>
  </template>

</div>


<!-- Vue -->
<script>
  var app = new Vue({
    el: '#hoge',
    data: {
      hoges: [{
          name: 'ほげ太郎',
          id: 1
        },
        {
          name: 'ほげ次郎',
          id: 2
        },
        {
          name: 'ほげ三郎',
          id: 3
        }
      ]
    }
  })
</script>

```

<img width="467" alt="DevTools_-_file____Users_hashimototakuma_Library_Mobile_20Documents_com_apple_CloudDocs_vue_learning_html_と_learning_html.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411729/a1b41547-fa28-0205-233a-bf09c0bca6bb.png">


※v-ifにおいても同様にtemplateタグを使うことで要素を出力せずに判定が可能



# コンポーネントを使いこなす
コンポーネントとは、再利用可能なVueインスタンス。要素の塊・UIの部品。
'使いまわせるテンプレートのようなもの`と思ってもらえればわかりやすいかも

```html

<!-- HTML -->
<div id="hoge">
  <hoge_component></hoge_component> <!-- ほげえええええええ -->
</div>


<!-- Vue -->
<script>
  Vue.component(hoge_component', {
    template: '<h1>ほげえええええええ</h1>'
  })

  var app = new Vue({
    el: '#hoge'
  })
</script>
```

このとき、`<hoge_component>`が`<h1>ほげえええええええ</h1>`に置き換わっているのが確認できる。


次にVue.componentの使い方をみてみよう

`tag_name`には、要素（テンプレート)を展開したいタグ名を、
`html_element`には、展開する予定のHTML要素(テンプレート)を記述する。

```vuejs
Vue.component(tag_name, {template: 'html_element'})
```


## グローバルなコンポーネントを定義する

Vueオブジェクトが指定する`el`内であれば、コンポーネントは使い回すことができる。

```html
<!-- HTML -->
<div id="hoge">
  <hoge_component> </hoge_component> <!-- ほげえええええええ -->
</div>

<div id="hogehoge"">
  <hoge_component> </hoge_component> <!-- ほげえええええええ -->
</div>

<!-- Vue -->
<script>
  Vue.component('hoge_component', {
    template: '<h1>ほげえええええええ</h1>'
  })

  var hoge = new Vue({
    el: '#hoge'
  })

  var hogehoge = new Vue({
  el: '#hogehoge'
  })
</script>
```

## ローカルなコンポーネントを定義する


```html
<!-- HTML -->
<div id="hoge">
  <hogecomponent> </hogecomponent> <!-- ほげええええええ!!! -->
</div>
<div id="hogehoge">
  <hogecomponent> </hogecomponent>
</div>

<!-- Vue -->
<script>
  var local_component = {
    template: '<div class="component">ほげええええええ!!!</div>'
  };
  var hoge = new Vue({
    el: '#hoge',
    components: {
      'hogecomponent': local_component
    }
  });
  var hogehoge = new Vue({
    el: '#hogehoge'
  });
</script>
```

この部分でコンポーネントのローカル化を行っている。

```vue
components: {
      'hogecomponent': local_component
    }
```

使い方はこのような感じ

```html
components: {
      '展開するタグ名': `templateを定義した変数・定数`
    }
```


## コンポーネントにプロパティを定義する


### props

コンポーネントにも`props`でプロパティを定義することができる。
このプロパティは、コンポーネントを呼び出す時に、任意の値を与えることができる。
親から子コンポーネントへ値を渡すときなどに使用される。プロパティというよりも`引数`のイメージに近いかも


```html
<!-- HTML -->
<div id="hoge">
  <hogecomponent hoge_property='ほげええエェxえぇ'></hogecomponent> <!-- ほげええエェxえぇ -->
</div>

<!-- Vue -->
<script>
  Vue.component('hogecomponent', {
    props: ['hoge_property'],
    template: '<h3>{{ hoge_property }}</h3>'
  });
  var hoge = new Vue({
    el: '#hoge'
  });
</script>
```

#### propsにvalidationを加える


- propsの方を指定する場合

今回はNumberを型指定したところにあえて、Stringを代入してみる

```html
<!-- HTML -->
<div id="hoge">
  <hogecomponent hoge_property='Hogeeeee'></hogecomponent> <!-- ほげええエェxえぇ -->
</div>

<!-- Vue -->
<script>
  Vue.component('hogecomponent', {
    props: {
      hoge_property: {
        type: Number,
      }
    },
    template: '<h3>{{ hoge_property }}</h3>'
  });
  var hoge = new Vue({
    el: '#hoge'
  });
</script>
```

<img width="1161" alt="DevTools_-_file____Users_hashimototakuma_Library_Mobile_20Documents_com_apple_CloudDocs_vue_learning_html_と_learning_html.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411729/f6eab022-ec1d-3334-0fb3-024c2c80d3ef.png">

実のところ、型を指定したからといって、表示が変わるわけではない。
しかし上記のようなエラーメッセージが出力される。


- requiredを指定した場合

```html
<!-- HTML -->
<div id="hoge">
  <hogecomponent></hogecomponent> <!-- ほげええエェxえぇ -->
</div>

<!-- Vue -->
<script>
  Vue.component('hogecomponent', {
    props: {
      hoge_property: {
        required: true,
      }
    },
    template: '<h3>{{ hoge_property }}</h3>'
  });
  var hoge = new Vue({
    el: '#hoge'
  });
</script>
```

<img width="654" alt="DevTools_-_file____Users_hashimototakuma_Library_Mobile_20Documents_com_apple_CloudDocs_vue_learning_html_と_learning_html.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411729/da9b250e-0ce9-b6aa-5e97-eec9706e3493.png">

同様に、あくまでも`warning`は出るが、描写自体への影響はない


- 独自のvalidationを追加した場合

```html
<!-- HTML -->
<div id="hoge">
  <hogecomponent hoge_property='hogehoge'></hogecomponent> <!-- ほげええエェxえぇ -->
</div>

<!-- Vue -->
<script>
  Vue.component('hogecomponent', {
    props: {
      hoge_property: {
        validator: function(value) {
          return value.lrngth < 100;
        }
      }
    },
    template: '<h3>{{ hoge_property }}</h3>'
  });
  var hoge = new Vue({
    el: '#hoge'
  });
</script>
```

<img width="1105" alt="DevTools_-_file____Users_hashimototakuma_Library_Mobile_20Documents_com_apple_CloudDocs_vue_learning_html_と_learning_html.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411729/8c98eaf6-8df4-86c3-80bf-8f880eccb8ac.png">



### 内部プロパティ

一方で`data`で定義されるのは内部プロパティ。外部から引数を受け付けて、どうこう操作できるものではない。
注意しなければならないのは、内部プロパティを定義する際は必ず`function()`を使って定義しなければならないこと。


```html

<!-- HTML -->
<div id="hoge">
  <hogecomponent></hogecomponent>
</div>

<!-- Vue -->
<script>
  Vue.component('hogecomponent', {
    data: function () {
      return {
        count: 0
      }
    },
    template: '<button v-on:click="count++">ほげカウント：{{ count }} times.</button>'
  });
  new Vue({
  el: '#hoge'
  });
</script>
```


[![Image from Gyazo](https://i.gyazo.com/863596fbce75e515ba4be9723f2d794e.gif)](https://gyazo.com/863596fbce75e515ba4be9723f2d794e)


## slotを使って文字を置き換える

ちょうど`<slot> ~ </slot>`で書き込まれた部分が`げげげげげげげげ`と置き換わっている。

```html
<!-- HTML -->
<div id="hoge">
  <hogecomponent>げげげげげげげげ</hogecomponent> <!-- ほほほほげげげげげげげげほほほほほ -->
</div>

<!-- Vue -->
<script>
  Vue.component('hogecomponent', {
    template: '<h3>ほほほほ<slot>ほほほ</slot>ほほほほほ</h3>'
  });
  var hoge = new Vue({
    el: '#hoge'
  });
</script>
```