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

#What is this ?
プログラミングの「プ」の字もわからなかった入社2年目が新たにVue.jsを学習していき、分かったことをまとめる日記です。
次章: [Re:ゼロから始めるVue.js生活](https://qiita.com/hashimotologly/items/ddc62d4d3c16b395df68)

# Why Vue ?
会社の新プロジェクトでVueを使って新しく画面設計を行うことになりました。
Vueの他にもReactなどのフレームワークも候補に上がりました。
ただ、VueはHTMLベースでコードを書くことができることや、便利なディレクティブなど、比較的学習コストを抑えて実装に取り掛かることができるようです。
今回は、納期に限りがある中、早めに取り掛かることが可能なVueに軍配が上がりました。

# Vue.jsを始めてみよう！

まずは手軽にVue.jsを始めてみよう

↓こちらで試し撃ちができるようです。
[CodePen Home Vue.js Playground](https://codepen.io/cotne95/pen/zKowbw)

また、CDNとしても提供されているので、HTML中にこちらを挿入することでローカル環境でも使えるようになリマス。

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

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


## Vueインスタンスを使いこなす
まずは以下のコードを打ち込んだhtmlを表示して、画面に「ほげぇぇぇぇぇぇぇぇ」を出力してみよう

```html
<!-- HTML -->
<div>--------------</div>
<div id="hoge">
  {{ message }}
</div>
<div>--------------</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: '#hoge',
    data: {
      message: 'ほげぇぇぇぇぇぇぇぇ'
    }
  })
</script>
<!-- Vue -->
```

..するとこのような表示が確認できる

```html
--------------
ほげぇぇぇぇぇぇぇぇ
--------------
```

このとき、
Vueコード側では

- `new Vue()`でVueインスタンスを作成
- `el:`で適用する範囲を指定
- `data:`でプロパティを設定（`app.message`として参照可）

一方、HTML側では、

- `{{ message }}` で `data: {message:`を参照し、展開している


### dataに階層構造を作る

dataプロパティはこのように子プロパティをネストすることが可能

```html

<!-- HTML -->
<div>--------------</div>
<div id="hoge">
  {{ oya_hoge.kodomo_hoge }} <!-- hogeeeee -->
</div>
<div>--------------</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: '#hoge',
    data: {
      oya_hoge:
        {
          kodomo_hoge: 'hogeeeee'
        }
    }
  })
</script>
<!-- Vue -->
```


### mustache {{ }} について

`{{ }}`では、vueのプロパティだけではなく、JavaScriptコードを展開可能

```html

<!-- HTML -->
<div class="hoge">
  {{ message + '?????' }} <!--ほげぇぇぇぇぇぇぇぇ?????-->
  {{ Math.abs(-999999)}} <!--999999-->
</div>
<!-- HTML -->
```


### el:　について

#### `el:`で指定したタグ以外では、`message`は展開できない

```html
<!-- HTML -->
<div class="not_hoge">
  {{ message }} <!--{{ message }}-->
</div>

<div class="hoge">
  {{ message }} <!--ほげぇぇぇぇぇぇぇぇ-->
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: ".hoge",
    data: {
      message: "ほげぇぇぇぇぇぇぇぇ",
    },
  });
</script>
<!-- Vue -->
```

ただし、指定したタグ配下であれば、どこであっても展開できる

```html
<!-- HTML -->
<div class="hoge">
    {{ message }} <!--ほげぇぇぇぇぇぇぇぇ-->
    <div class="in_hoge">
      {{ message }} <!--ほげぇぇぇぇぇぇぇぇ-->
    </div>
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: ".hoge",
    data: {
      message: "ほげぇぇぇぇぇぇぇぇ",
    },
  });
</script>
<!-- Vue -->
```

#### 複数のタグを対象とすることはできない
`el:`が適用されるタグは必ず１つ。
したがって、同じクラス名をもつタグを複数作っても、先頭のタグ内のみ`message`が展開される。

```html
<!-- HTML -->
<div class="hoge">
  {{ message }} <!--ほげぇぇぇぇぇぇぇぇ-->
</div>
<div class="hoge">
  {{ message }} <!--{{ message }}-->
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: ".hoge",
    data: {
      message: "ほげぇぇぇぇぇぇぇぇ",
    },
  });
</script>
<!-- Vue -->

```

### 同一の親ノード内で、既にあるプロパティは定義できない

今回は、`app.message`を先に定義しているので`message: "ほげぇぇぇぇぇぇぇぇ"`が優先されて適用されている。
ノードの親子関係は関係なく、先に書いてある方が優先して適用されるので注意されたし。

```html
<!-- HTML -->
<div class="hoge">
  <div class="under_hoge">
    {{ message }} <!-- ほげぇぇぇぇぇぇぇぇ -->
  </div>
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: ".hoge",
    data: {
      message: "ほげぇぇぇぇぇぇぇぇ",
    },
  });

  var app2 = new Vue({
    el: ".under_hoge",
    data: {
      message: "Hogeeee",
    },
  });
</script>
<!-- Vue -->
```



## ディレクティブを使いこなす

ディレクティブというのは`v-bind`や`v-html`など、`v-`で始まる命令文のこと。
`v-`の後に続く命令によってVueは処理を切り替えている。

### v-bindを使いこなす

`v-bind`では、htmlタグの属性値(href,class,id...)を動的に変化させることができる。

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


<!-- HTML -->
<ul id="hoge">
  <li v-for="hoge in hoges"　v-bind:key="hoge.id">
    {{ hoge.name }}
    {{ hoge.id }}
  </li>
</ul>
<!-- HTML -->

<!-- Vue -->
<script>
  var example1 = new Vue({
    el: '#hoge',
    data: {
      hoges: [{
          name: 'hoge_FIRST',
          id: 1
        },
        {
          name: 'hoge_SRCOND',
          id: 2
        }
      ]
    }
  })
</script>
<!-- Vue -->

```

- `v-bind:href`で、href属性を変更することを宣言
- `v-bind:href="vue_href"`で、`data: {vue_href:`を参照し、展開

classを変更する時は、既存classに加えて、新たにclassを追加する。

```html
<!-- HTML -->
<div class='hoge'  v-bind:class="vue_class"></div> <!--<div class="hoge hogeeeee"></div>-->
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: ".hoge",
    data: {
      vue_class: "hogeeeee",
    },
  });
</script>
<!-- Vue -->
```

idを変更する場合は、既存idを上書きしてしまうので注意


#### v-bindの省略記法
また、`v-bind`はよく使われるため、このように省略されることがままある。

```html
<div class='hoge'  v-bind:class="vue_class"></div>
```
これを、`v-bind:`を省略して`:`と書くことが可能

```html
<div class='hoge'  :class="vue_class"></div>
```

### v-htmlを使いこなす

`v-html`を使うことで、エスケープ処理が行われなくなる。
任意のHTML要素を動的に出したい場合に役に立つ

```html
<!-- HTML -->
<div>-----------</div>
<div class='hoge' v-html="html_message"></div>
<div>-----------</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: ".hoge",
    data: {
      html_message: "<h1>ほげええええええ</h1>",
    },
  });
</script>
<!-- Vue -->
```
出力すると、しっかり`<H1>`タグが機能していることがわかる
<img width="425" alt="VueArtic_html.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411729/4feaa48a-31f2-9fe7-97ca-2b3fb7817820.png">

### v-ifを使いこなす

`visible = true`であれば`<button>`タグが生成される

```html
<!-- HTML -->
<div id="hoge">
  <button v-if="visible">ほげボタン</button> <!-- ほげボタン -->
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: '#hoge',
    data: {
      visible: true
    }
  })
</script>
<!-- Vue -->
```

else文もこのように使うことができる


```html
<!-- HTML -->
<div id="hoge">
  <div>{{now}}</div>
  <button v-if="visible">ほげボタン</button>
  <button v-else="visible">ホゲってないぞ</button> <!-- ホゲってないぞ -->
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: '#hoge',
    data: {
      visible: false
    }
  })
</script>
<!-- Vue -->
```

### v-showを使いこなす

`visible = true`であれば`<button>`タグが生成される

```html
<!-- HTML -->
<div id="hoge">
  <button v-show="visible">ほげボタン</button> <!-- ほげボタン -->
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: '#hoge',
    data: {
      visible: true
    }
  })
</script>
<!-- Vue -->
```

#### v-ifとの違いについて

`v-if`では、条件が`false`の場合、`タグ自体が生成されない`のに対して、
`v-show`では`タグそのものは存在するが見えない(display: none;)`となる

したがって、表示切り替えを頻繁に行うなら`v-show`、
たまに行う程度なら`v-if`という使い分けになると考えられる。

## v-forを使いこなす
v-forを使うことで、入れ子状になったプロパティや配列を順に取り出すことができる

```html
<!-- HTML -->
<ul id="hoge">
  <li v-for="hoge in hoges" v-bind:key="hoge.id">
    {{ hoge.name }}
    {{ hoge.id }}
  </li>
</ul>

<!-- Vue -->
<script>
  var example1 = new Vue({
    el: '#hoge',
    data: {
      hoges: [{
          name: 'hoge_FIRST',
          id: 1
        },
        {
          name: 'hoge_SRCOND',
          id: 2
        }
      ]
    }
  })
</script>

```
<img width="424" alt="learning_html.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411729/55c9c090-fbf3-b092-117f-fff4635c6a86.png">


流れとしては、
- `v-bind:key`で重複しない一意なプロパティ名を指定(Vue.js 2.2.0より`v-bind:key`の指定は必須)
- `hoge in hoges`で`hoges`から要素を一つずつ、`hoge`として取り出す
-  ```{{ hoge.name }},{{ hoge.id }}```でプロパティにアクセス
-  次の`hoge`を取り出す...


### データオブジェクトに対してv-forを使った場合

#### 第二引数を指定できる
第一引数(value)にプロパティの値が、第二引数(property_name)にプロパティ名が入ってくる

```html
<!-- HTML -->
<ul id="hoge">
  <li v-for="(value,property_name) in hoge_obj">
    {{ property_name }}, {{ value }}
  </li>
</ul>


<!-- Vue -->
<script>
  var example1 = new Vue({
    el: '#hoge',
    data: {
      hoge_obj: {
        name: 'hoge_FIRST',
        id: 1
      }
    }
  })
</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/e46c7963-0158-ddbb-dcfa-3301afa9c186.png">


#### 第三引数を指定できる
第三引数にはインデックス番号(何番目の要素か)が格納されている

```html

<!-- HTML -->
<ul id="hoge">
  <li v-for="(value,property_name,index) in hoge_obj">
    {{ property_name }}, {{ value }}, {{index}}
  </li>
</ul>


<!-- Vue -->
<script>
  var example1 = new Vue({
    el: '#hoge',
    data: {
      hoge_obj: {
        name: 'hoge_FIRST',
        id: 1
      }
    }
  })
</script>
```

<img width="289" alt="learning_html.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411729/88c0a241-43b3-3d41-b331-c35e88c0b82f.png">









## メソッドを使いこなす

```html
<!-- HTML -->
<div class='hoge'>
  {{hoge_func()}} <!-- ほげえええええええ -->
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: ".hoge",
    methods: {
      hoge_func: function () {
        return "ほげえええええええ"
      }
    },
  });
</script>
<!-- Vue -->
```

### メソッドに引数をとる
```html
<!-- HTML -->
<div class='hoge'>
  {{hoge_func('ほゲゲゲゲゲゲ')}} <!-- ほゲゲゲゲゲゲ?????? -->
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: ".hoge",
    methods: {
      hoge_func: function (argument) {
        return argument+'??????'
      }
    },
  });
</script>
<!-- Vue -->
```

## 算出プロパティ(computed)を使いこなす

```html
<!-- HTML -->
<div id="hoge">
  {{ hogeReverse }} <!-- ぇぇぇぇぇぇぇぇげほ -->
</div>
<!-- HTML -->

<!-- Vue -->
<script>
  var app = new Vue({
    el: '#hoge',
    data: {
      message: 'ほげぇぇぇぇぇぇぇぇ'
    },
    computed: {
      hogeReverse: function () {
        return this.message.split("").reverse().join(""); //文字列を反転させる
      }
    }
  })
</script>
<!-- Vue -->

```

ここで、
- `this`はappインスタンスを表している(this.hogeReverse = app.hogeReverseと同等)
- このthisは省略できない（```message is not defined```)

また、
あくまでcomputedで定義されるのは`プロパティ`であって、`メソッド`ではないので引数を取ることはできない

```
hogeReverse() ❌
hogeReverse(arg) ❌
```