【学習メモ】Vue.jsのチュートリアルやってみる（1~8章）

# 初めに
仕事でたまにVue.jsを使う機会があるのですが、よく分かっていなかったので一から学びました。
学んだことをアウトプットします。

# 使用したサイト
全15章。今回は1~8章。
https://ja.vuejs.org/tutorial/#step-1

# 学習メモ

## 宣言的レンダリング
宣言した値をHTML上で表示させることができる。

* `data()`の中でプロパティを定義
* HTML内で二重中括弧`{{ }}`で囲む

```vuejs
<script type="module">
import { createApp } from 'vue'

createApp({
  data() {
    return {
      message: 'Hello World!'
    }
  }
  // component options
  // declare some reactive state here.
}).mount('#app')
</script>

<div id="app">
  <h1>{{ message.split('').reverse().join('') }}</h1>
</div>
```

## 属性バインディング
vueで宣言したプロパティを属性にバインドする。

* `<h1 v-bind:class="titleClass">`のように`v-bind:class="dynamicClass"`のように、`v-bind`をつけることで動的な値をバインドする
* `v-bind`は省略して`:class="dynamicClass"`のように書くことも可能

```vuejs
<script type="module">
import { createApp } from 'vue'

createApp({
  data() {
    return {
      titleClass: 'title'
    }
  }
}).mount('#app')
</script>

<div id="app">
  <h1 v-bind:class="titleClass">Make me red</h1> <!-- add dynamic class binding here -->
</div>
```

## イベントリスナー
ボタンがクリックされた時など、DOMイベント時の処理を定義できる。

* vue上で`methods`オプションを作成し、その中にメソッドを作成する
* プロパティを呼ぶときは`this.count`のようにする
* HTML上では`<button v-on:click="incliment">`のようにする
* `v-on:click`は`@click`と省略可能

```vuejs
<script type="module">
import { createApp } from 'vue'

createApp({
  data() {
    return {
      count: 0
    }
  },
  methods: {
    incliment() {
      this.count++
    }
  }
}).mount('#app')
</script>

<div id="app">
  <!-- make this button work -->
  <button v-on:click="incliment">Count is: {{ count }}</button>
</div>
```

## フォームバインディング
`v-bind`と`v-on`を用いて、input要素に双方向バインディングを作成することができる

```vuejs
<script type="module">
import { createApp } from 'vue'

createApp({
  data() {
    return {
      text: ''
    }
  },
  methods: {
    onInput(e) {
      // v-on ハンドラーはネイティブDOMのイベントを
      // 引数として受け取ります。
      this.text = e.target.value
    }
  }
}).mount('#app')
</script>

<div id="app">
  <input v-on:value="text" v-bind:input="onInput">
  <p>{{ text }}</p>
</div>
```


これらはv-modelで省略可能

```vuejs
<script type="module">
import { createApp } from 'vue'

createApp({
  data() {
    return {
      text: ''
    }
  },
  methods: {
    // 不要
    // onInput(e) {
    //   this.text = e.target.value
    // }
  }
}).mount('#app')
</script>

<div id="app">
  <input v-model="text" placeholder="Type here">
  <p>{{ text }}</p>
</div>
```

## 条件付きレンダリング
条件付きで表示する場合、`v-if`を用いる
`v-else`や`v-else-if`は`v-if`直後の要素にしか用いることができない

```vuejs
<script type="module">
import { createApp } from 'vue'

createApp({
  data() {
    return {
      awesome: true
    }
  },
  methods: {
    toggle() {
      this.awesome = !this.awesome
    }
  }
}).mount('#app')
</script>

<div id="app">
  <button @click="toggle">Toggle</button>
  <h1 v-if="awesome">Vue is awesome!</h1>
  <h1 v-else>Oh no 😢</h1>
</div>
```

## リストレンダリング
リストの要素をレンダリングしたい時は`v-for`ディレクティブを用いる
```vuejs
<script type="module">
import { createApp } from 'vue'

// give each todo a unique id
let id = 0

createApp({
  data() {
    return {
      newTodo: '',
      todos: [
        { id: id++, text: 'Learn HTML' },
        { id: id++, text: 'Learn JavaScript' },
        { id: id++, text: 'Learn Vue' }
      ]
    }
  },
  methods: {
    addTodo() {
      this.todos.push({ id: id++, text: this.newTodo })
      this.newTodo = ''
    },
    removeTodo(todo) {
      this.todos = this.todos.filter(t => t !== todo)
    }
  }
}).mount('#app')
</script>

<div id="app">
  <form @submit.prevent="addTodo">
    <input v-model="newTodo" required placeholder="new todo">
    <button>Add Todo</button>
  </form>
  <ul>
    <li v-for="todo in todos" :key="todo.id">
      {{ todo.text }}
      <button @click="removeTodo(todo)">X</button>
    </li>
  </ul>
</div>
```

## 算出プロパティ
通常のプロパティと違い、処理を記述することができる

computedオプションを作成し、その中で宣言を行う。
methodsとの違いは
* 引数を指定できない
* 値をキャッシュする

```vuejs
<script type="module">
import { createApp } from 'vue'

let id = 0

createApp({
  data() {
    return {
      newTodo: '',
      hideCompleted: false,
      todos: [
        { id: id++, text: 'Learn HTML', done: true },
        { id: id++, text: 'Learn JavaScript', done: true },
        { id: id++, text: 'Learn Vue', done: false }
      ]
    }
  },
  computed: {
    filteredTodos() {
      return this.hideCompleted
        ? this.todos.filter((t) => !t.done)
        : this.todos
    }
  },
  methods: {
    addTodo() {
      this.todos.push({ id: id++, text: this.newTodo, done: false })
      this.newTodo = ''
    },
    removeTodo(todo) {
      this.todos = this.todos.filter((t) => t !== todo)
    }
  }
}).mount('#app')
</script>

<div id="app">
  <form @submit.prevent="addTodo">
    <input v-model="newTodo" required placeholder="new todo">
    <button>Add Todo</button>
  </form>
  <ul>
    <li v-for="todo in filteredTodos" :key="todo.id">
      <input type="checkbox" v-model="todo.done">
      <span :class="{ done: todo.done }">{{ todo.text }}</span>
      <button @click="removeTodo(todo)">X</button>
    </li>
  </ul>
  <button @click="hideCompleted = !hideCompleted">
    {{ hideCompleted ? 'Show all' : 'Hide completed' }}
  </button>
</div>
```

# 終わりに
いつもなんとなく書いているVue.jsが少しわかってきました。
まだチュートリアル半分なので、残り半分もやっていきたいです。

ここまでご覧いただきありがとうございました！