Vue.jsの基礎機能をサクッと見たい時用のメモ

# はじめに
Vue.jsで使用できる機能を一通りサクッと見返したいとき用に作成しました。
詳しい解説まではありませんが、参考になれば幸いです。
<br>
<br>

# ◆ データをそのまま表示

## ◎ マスタッシュ　{{ }}　を使ってそのまま表示

**■構文**
```vuejs
{{ プロパティ名　}}
```

**■例文**

```vuejs
<template>
  <div id="app">
    <h1>{{message}}</h1>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Welcome to Vue!'
    };
  },
};
</script>
```
<br>
<br>

## ◎ ディテクティブを使って表示

**■構文**
```vuejs
<p v-text="プロパティ名"></p>
 
<p v-html="プロパティ名"></p>
```

**■例文**
```vuejs
<template>
  <div id="app">
    <h1 v-text="message"></h1>
    <h1 v-html="message_html"></h1>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Welcome to Vue!',
      message_html: '<p>Welcome Vue & HTML!</p>'
    };
  },
};
</script>
```
<br>
<br>

# ◆ 表示できるデータの種類

基本的にはどの型も表示可能。また、メソッドと合わせて記載して表示することもできる。

**■例文**
```vuejs
<template>
  <div id="app">
      <p>{{ str }}</p>
      <p>{{ bool }}</p>
      <p>{{ num }}</p>
      <p>{{ arr }}</p>
      <p>{{ arr[0]}}</p>
      <p>{{price}}</p>
      <p>{{price.banana}}</p>
      <p>{{profile}}</p>
      <p>{{profile[0].name}}</p>
  
      <!--  メソッドの使用も可能  -->
      <p>{{ str.substring(0,1) }}</p>

      <!--  データの中身（data())を全て確認する  -->
      <p>{{ $data }}</p>
      <ul>
        <li v-for="(item, key) in $data" :key={{key}}>{{key}} : {{item}}</li>
      </ul>
  </div>
</template>

<script>
export default {
  data() {
   return {
      // string
      str: 'Hello Vue!!',
      // boolean
      bool: true,
      // number
      num: 100,
      // array
      arr:["html", "css", "vue"],
      arr2: [10, 20, 30],
      // object
      price: {
        apple: 100,
        grape: 200,
        banana: 300,
      },
      // array + object
      profile: [
        {name: "george", age: 33},
        {name: "sarry", age: 20},
        {name: "bosh", age: 19} 
      ],
    }
  }
};
</script>
```
<br>
<br>

# ◆ 属性を指定する

## ◎ v-bindで要素の属性をデータで指定

**■構文**

```vuejs
<a v-bind:属性="プロパティ名"></a>
 
<!-- 省略形 -->
<a :属性="プロパティ名"></a>
```

**■例文**
```vuejs
<template>
  <div id="app">
      <!--  リンクの指定  -->
      <a :href="Link">LINK</a>

      <!--  スタイルの指定  -->
      <p :style="{ color: myColor }">RED</p>

      <!--  classの指定  -->
      <p :class="myClass">CLASS</p>

      <!--  classの指定（複数）  -->
      <p :class="[ myClass, center ]">SOME CLASS</p>

      <!--  classの指定（booleanによる判定）  -->
      <p :class="{ demoClass: isON }">CLASS</p>
      <p :class="{ demoClass: isOFF }">CLASS</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      Link: "",
      myColor: "red",
      myClass: "demoClass",
      center: "center",
      isON: true,
      isOFF: false,
    }
  },
};
</script>

<style>
.demoClass {
  color: blue;
  width: 100px;
  background-color: lime;
}
.center {
  text-align: center;
}
</style>
```
<br>
<br>

# ◆ユーザーの入力をつなぐ時

## ◎ v-modelディテクティブを使用する。

VueインスタンスのデータがWeb上に表示され、かつユーザーの入力情報がVueインスタンスのデータに反映されることから、`双方型バインディング`と呼ばれる。

**■構文**

```vuejs
<タグ v-model="プロパティ名"></タグ>
 
<!-- 省略形 -->
<a :属性="プロパティ名"></a>
```

**■例文**

### ・inputタグ
```vuejs
<div id="hello-vue" class="demo">
  <!--  inputに入力した値が、下のpに反映され、表示される。  -->
  <input type="text" v-model="myText">
  <p>{{myText}}</p>
</div>

<script>
export default {
  data() {
    return {
      myText: "",
    }
  },
};
</script>
```
<br>

### ・checkboxタグ
```vuejs
<div id="hello-vue" class="demo">
  <!--  checkboxのチェックの有無で、myCheckの表示がtrue・falseに切り替わる  -->
  <label>チェック
  <input type="checkbox" v-model="myCheck">
  </label>
  <p>チェックボックスは現在{{myCheck}}です。</p>
</div>
</div>

<script>
export default {
  data() {
    return {
      myCheck: false,
    }
  },
};
</script>
```
<br>

### ・checkboxタグ②
チェックボックスでは、複数のチェックボックスに同じプロパティをバインドすることで、
一つのグループとしてまとめて扱うことができるようになる。
この時、`データ型は配列`になる。
またそれぞれのチェックボックスに対し、`異なるvalueの値を設定する`ことが必須。
これにより、チェックボックスの区別をする。

```vuejs
<div id="hello-vue" class="demo">
  <!--  checkboxのチェックの有無で、設定したvalueの値がmyChecks配列に入り、表示される  -->
  <label>チェック
  <input type="checkbox" value="red" v-model="myChecks">
    <input type="checkbox" value="blue" v-model="myChecks">
    <input type="checkbox" value="green" v-model="myChecks">
  </label>
<!--  ["red", "blue", "green"]と表示  -->
  <p>{{myChecks}}</p>
</div>

<script>
export default {
  data() {
    return {
      myChecks: [],
    }
  },
};
</script>
```

<br>

### ・checkboxタグ（応用）

チェックボックスとボタンタグを使い、「同意する」のチェックをつけたらボタンが活性化するという処理を実装する。

```vuejs
<div id="hello-vue" class="demo">
  <input type="checkbox" v-model="myCheck">同意します。
  <button :disabled="!myCheck">ボタン</button>
</div>

<script>
export default {
  data() {
    return {
      myCheck: false,
    }
  },
};
```
<br>

### ・radioボタン

v-modelでバインディングすることで、選択された値だけがデータとして管理される。
連携の仕方は複数パターンのチェックボックスと同じ。

v-modelで`同じプロパティを設定し`、
valueに`異なる値を設定する`ことで判別する。

テキスト表示だけでなく、クラスなどの属性にもバインドすることで、スタイルを動的に変更するなどの使い方ができる。
```vuejs
<template>
  <div :class="myRadio">
    <label> <input type="radio" value="red" v-model="myRadio" />赤 </label>
    <label> <input type="radio" value="blue" v-model="myRadio" />青 </label>
    <label> <input type="radio" value="green" v-model="myRadio" />緑 </label>
    <p>{{ myRadio }}</p>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      /**
       * 初期値を設定しておくことで、
       * 初期表示時に設定したvalueのradioボタンが
       * チェックされた状態になる。
       */
      myRadio: "red",
    };
  },
};
</script>

<style>
.red {
  color: red;
}
.blue {
  color: blue;
}
.green {
  color: green;
}
</style>
```
<br>

### ・select

radioと同様、基本は選択したデータ一つを、Vueインスタンスで管理する。

```vuejs
<template>
  <div>
<!-- selectタグでv-modelを使用したら、あとは選択したoptionの値がデータとして設定される。 -->
    <select v-model="mySelect">
      <option disabled value="">非選択時（例：色を選択してください）</option>
      <option>red</option>
      <option>blue</option>
      <option>green</option>
      <option>yellow</option>
    </select>
  </div>
  <p :style="{ color: mySelect }">Your select is {{ mySelect }}</p>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      mySelect: "",
    };
  },
};
</script>
```
<br>

### ・select②

選択した値を複数保持しておくことも可能。
そのようにする場合は、selectタグに`multiple`と記載し、
Vueインスタンスの対象データのデータ型を配列にする。

```vuejs
<template>
  <div>
<!-- selectタグでv-modelを使用したら、あとは選択したoptionの値がデータとして設定される。 -->
    <select v-model="mySelect" multiple>
      <option disabled value="">非選択時（例：色を選択してください）</option>
      <option>red</option>
      <option>blue</option>
      <option>green</option>
      <option>yellow</option>
    </select>
  </div>
  <p :style="{ color: mySelect }">Your select is {{ mySelect }}</p>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      mySelect: [],
    };
  },
};
</script>
```
<br>
<br>

# ◆ユーザーの操作をつなぐ時

## ◎ v-onディテクティブを使用する

**■構文**

```vuejs
<タグ v-on:イベント="メソッド名"></タグ>
 
<!-- 省略形 -->
<タグ @イベント="メソッド名"></タグ>
```

`methodsオプション`を新たに追加し、イベントが発生した時に実行される命令を定義しておく。

```
methods: { ... }
```

**■例文**

```vue
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <div>
    <button @click="toggle">TOGGLE</button>
    <!-- ボタンを押すと文字の色と表記がtrue・false　で切り替わる -->
    <p :class="{ red: isBool }">isBoolは{{ isBool }}です。</p>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      isBool: false,
    };
  },
  methods: {
    toggle() {
      this.isBool = !this.isBool;
    },
  },
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
.red {
  color: red;
}
.blue {
  color: blue;
}
.green {
  color: green;
}
</style>

```

## ◎キー操作でメソッドを実行することも可能。

**■構文**

```vuejs
<タグ v-on:keyup.キー修飾子="メソッド名"></タグ>
```

### ■key一覧

| key1 | key2 |
| :-:  | :-: |
|**.enter**|**.down**|
|**.tab**|**.left**|
|**.esc**|**.right**|
|**.space**|**.48~.57(0 ~ 9)**|
|**.up**|**.48~.57(A ~ Z)**| 

<br>

### 【 ポイント 】
キー修飾子を指定しなければ、どのキーを押しても実行される。
特定のキーを押した場合のみ実行したいときに設定するのが良い。

**■例文**

```vuejs
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <div>
    <!-- 文字を入力してEnterを押すと、入力された文字がalertにも反映されて表示 -->
    <input v-on:keyup.enter="openAlert(myText)" v-model="myText" />
    <!-- inputに入力された文字が表示される。 -->
    <p>{{ myText }}</p>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      myText: "",
    };
  },
  methods: {
    openAlert(str) {
      alert("Enterが押されました。入力値 ＝ " + str);
    },
  },
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
.red {
  color: red;
}
.blue {
  color: blue;
}
.green {
  color: green;
}
</style>

```
<br>
<br>

## ◎システム修飾子キーで実行条件をより制限。

### ■key一覧

| 主な操作キー |
| :-: |
|**.ctrl**|
|**.alt**|
|**.shift**|
|**.meta**|

**■構文**
```vuejs
<タグ v-on:keyup.キー修飾子.システム修飾子キー="メソッド名"></タグ>
```

**■例文**

```vuejs
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <div>
    <!-- Enterだけでは実行されず、shift + Enter でのみメソッドが実行される -->
    <input v-on:keyup.enter.shift="openAlert(myText)" v-model="myText" />
    <!-- ボタンを押すと文字の色と表記がtrue・false　で切り替わる -->
    <p>{{ myText }}</p>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      myText: "",
    };
  },
  methods: {
    openAlert(str) {
      alert("Enterが押されました。入力値 ＝ " + str);
    },
  },
};
</script>

```
<br>
<br>

# ◆条件分岐と繰り返し

## ◎ 条件分岐はv-ifディテクティブを使用する。

**■構文**

```vuejs
<!-- パターン１ -->
<タグ v-if="条件文">条件がtrueなら表示</タグ>
<タグ v-else>そうでないならば表示</タグ>

<!-- パターン２ -->
<タグ v-if="条件文１">条件１がtrueなら表示</タグ>
<タグ v-else-if="条件文２">条件１でなく、条件２がtrueなら表示</タグ>
<タグ v-else>いずれも違う場合は表示</タグ>
```

**■例文**
```vuejs
<template>
  <img alt="Vue logo" src="./assets/logo.png" />

  <div :class="myText">
    <input type="text" v-model="myText">
    <!-- redと入力されたら、赤文字で表示される。 -->
    <p v-if="myText === myRed">Redと入力しました。</p>

    <!-- blueと入力されたら、青文字で表示される。 -->
    <p v-else-if="myText === myBlue">Blueと入力しました。</p>

    <!-- それ以外の場合に表示される -->
    <p v-else>該当なし</p>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      myText: "",
      myRed: "red",
      myBlue: "blue",
    };
  },
};
</script>

<style>
.red {
  color: red;
}
.blue {
  color: blue;
}
</style>
```
<br>

## ◎ v-ifと似た機能を持つv-show

v-showもv-ifと同様、trueのときに表示、falseなら非表示にするという機能を持つ。

**■構文**

```vuejs
<!-- パターン１ -->
<タグ v-show="条件文">条件がtrueなら表示 / falseなら非表示</タグ>
```

**■例文**
```vuejs
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <div :class="myText">
    <button @click="toggle">TOGGLE</button>
    <!-- trueなら表示 -->
    <p v-show="isBool">Hello !!</p>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      isBool: false,
    };
  },
  methods: {
    toggle() {
      this.isBool = !this.isBool;
    },
  },
};
</script>
```
<br>

### 【v-ifとの相違点】

①v-ifの結果が`false`の時は、HTML要素から完全に消えているのに対し、v-showは`HTML要素としては存在し続ける。`（CSSの display: none　と同様の状態）

②v-showはv-elseとの互換性はないので、`falseの場合には別のものを表示`という処理は行えない。

<br>
<br>

## ◎ 繰り返し処理の時はv-forディテクティブを使用する。

**■構文**

```vuejs
<!-- 配列の中身を１つずつ取り出して繰り返す -->
<タグ v-for="変数　in 配列">繰り返し表示する部分</タグ>

<!-- 最大回数分繰り返す -->
<タグ v-for="変数　in 最大値">繰り返し表示する部分</タグ>

<!-- 変数とindex番号を取り出して繰り返す -->
<タグ v-for="（変数、番号）　in 配列">繰り返し表示する部分</タグ>
```

**■例文(パターン１)**
```vuejs
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <div>
    <ul>
      <!-- 配列の中身を１つずつ順番に表示される -->
      <li v-for="arr in array" :key="arr">{{ arr }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      array: ["カエル", "オケラ", "アメンボ"],
    };
  },
};
</script>
```

<br>

**■例文(パターン2)**
```vuejs
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <div>
    <ul>
      <!-- 1~10が順番に表示される -->
      <li v-for="count in myCounts" :key="count">{{ count }}</li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      myCounts: 10,
    };
  },
};
</script>
```

<br>

**■例文(パターン3)**
```vuejs
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <div>
    <ul>
      <!-- 1:りんご〜　のようにindex:arrが順番に表示 -->
      <li v-for="(arr, index) in array" :key="index">
        {{ index }} : {{ arr }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      array: ["りんご", "バナナ", "メロン", "葡萄"],
    };
  },
};
</script>

```

<br>

**■例文(パターン4)**
配列のオブジェクトも展開・表示することが可能。
```vuejs
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <div>
    <ul>
      <li v-for="(obj, index) in arrObj" :key="index">
        {{ obj.name }} : {{ obj.age }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      arrObj: [
        {name: "jack", age: 11},
        {name: "queen", age: 12},
        {name: "king", age: 13},
        {name: "joker", age: 0},
      ],
    };
  },
};
</script>
```
<br>

## ◎ 配列の追加・削除では必ず push / splice

Vue.jsでは配列に何らかの変更を加えたいときには必ず`pushメソッド`か`spliceメソッド`を使用する必要がある。

**■構文**

```vuejs
<!-- 配列の末尾に追加 -->
配列名.push(追加するデータ)

<!-- 配列の○番目に追加（挿入） -->
配列名.splice(index, 0, 追加するデータ)

<!-- 配列の○番目に追加（更新） -->
配列名.splice(index, 1, 追加するデータ)

<!-- ○番目の配列を削除 -->
配列名.splice(index, 1)

※補足説明
spliceメソッドの 0 1 は削除するかしないかの判定。
0 → 削除しない
1 → 削除
```

<br>

**■例文**

```vuejs
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <div>
    <!-- 配列の末尾に追加 -->
    <form>
      名前：<input type="text" v-model="addText" /> 
      年齢：<input type="number" v-model="addAge />
      <button @click="add(addText, addAge)">追加</button>
    </form>

    <!-- inputに入力した数値番目の配列を削除 -->
    <form>
      <input type="number" v-model="deleteIndex" />番目
      <button @click="deleteArr(deleteIndex)">削除</button>
    </form>

    <!-- inputに入力した数値番目に値を挿入 -->
    <form>
      名前：<input type="text" v-model="insertText" /> 
      年齢：<input type="number" v-model="insertAge"/>
      <input type="number" v-model="insertIndex" />番目
      <button @click="insertArr(insertText, insertAge, insertIndex)">挿入
      </button>
    </form>

    <!-- inputに入力した数値番目の値を更新 -->
    <form>
      名前：<input type="text" v-model="updateText" /> 
      年齢：<input type="number" v-model="updateAge"/>
      <input type="number" v-model="updateIndex" />番目
      <button @click="updateArr(updateText, updateAge, updateIndex)">更新
      </button>
    </form>

    <ul>
      <li v-for="(obj, index) in arrObj" :key="index">
        {{ obj.name }} : {{ obj.age }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      addText: "",
      addAge: 0,
      deleteIndex: 0,
      insertName: "",
      insertAge: 0,
      insertIndex: 0,
      updateText: "",
      updateAge: 0,
      updateIndex: 0,
      arrObj: [
        { name: "jack", age: 11 },
        { name: "queen", age: 12 },
        { name: "king", age: 13 },
        { name: "joker", age: 0 },
      ],
    };
  },
  methods: {
     // 末尾に追加するメソッド
    add(myText, myAge) {
      const newObj = { name: myText, age: myAge };
      this.arrObj.push(newObj);
    },

    // 引数に指定した数字の配列を削除するメソッド
    deleteArr(index) {
      if (index > this.arrObj.length - 1) {
        alert(index + "番目の配列は存在しません。");
        return "";
      } else {
        this.arrObj.splice(index, 1);
      }
    },
    // 引数に指定した数字の配列をに新しい値を挿入するメソッド
    insertArr(text, age, index) {
      const newObj = { name: text, age: age };
      this.arrObj.splice(index, 0, newObj);
    },
    // 引数に指定した数字の配列の値を更新するメソッド
    updateArr(text, age, index) {
      const newObj = { name: text, age: age };
      this.arrObj.splice(index, 1, newObj);
    },
  },
};
</script>
```

<br>

### 【なぜpush / spliceを使う必要があるのか】
配列の値を変えるやり方としては以下の方法もあるが、このやり方ではVueが変化に気づけず、レンダリングされない（画面を更新してくれない）。

```vuejs
配列[index] = 新しい値
```
なので、配列の更新は必ずメソッドを利用すること。

<br>
<br>

# ◆ Computed（算出プロパティ）とは

Vue.jsでは、computed（算出プロパティ）オプションという機能がある。

この機能は、Vueインスタンスが持つdataの値が変化することを監視し、値に変更があった際に自動的に更新し、画面に反映してくれる。

<br>

**■構文**

```vue
<template>
    {{ computedプロパティ名 }}
</template>

<script>
    data() {
        return {...}
    },
    computed: {
        computedプロパティ名() {
            処理内容
        }
    },
</script>
```

<br>

**■例文 （消費税の計算）**

```vue
<template>
  <input type="number" v-model="price" />
  <br />
  <p>{{ taxInclude }}円</p>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      price: 100,
    };
  },
  computed: {
    taxInclude() {
      return Math.floor(this.price * 1.1);
    },
  },
};
</script>

```
<br>

■ 結果
input要素内の数値を変更すれば、消費税込みの数値を画面に表示してくれる。

![スクリーンショット 2023-06-02 2.27.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/07546868-efae-4a5b-5eaa-d5324064e6e1.png)

<br>

**■例文 （残りの入力文字数の表示と文字の色変更）**

```vuejs
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <br />
  <textarea v-model="myText"></textarea>
  <p :style="{ color: styleColor }">残り{{ length }}文字です。</p>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      myText: "",
      array: ["html", "css", "javascript", "php"],
    };
  },
  computed: {
    length() {
      return 140 - this.myText.length;
    },
    styleColor() {
      let col = "black";
      if (this.length < 20) {
        col = "red";
      } else if (this.length < 50) {
        col = "blue";
      } else if (this.length < 100) {
        col = "green";
      }
      return col;
    },
  },
};
</script>
```
<br>

■ 結果
textareaに文字を入力すると、残りの必要な文字数を表示。また、文字数に応じて文字の色を変更。

![スクリーンショット 2023-06-02 16.15.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/16c7bd85-748b-e34f-d665-beb6260dbb32.png)


<br>

**■例文 （inputに入力した文字を含むリストだけを表示）**

```vuejs
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <br />
  <input type="text" v-model="myFind" />
  <ul>
    <li v-for="arr in findArray" :key="arr">{{ arr }}</li>
  </ul>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      myText: "",
      array: ["html", "css", "javascript", "php"],
      myFind: "",
    };
  },
  computed: {
    findArray() {
      return this.array.filter((x) => {
        return x.includes(this.myFind);
      });
    },
  },
};
</script>
```

<br>

■ 結果
![スクリーンショット 2023-06-02 16.20.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/b0e052f5-f91c-552a-d0a2-be78d77c975e.png)

<br>

入力後
![スクリーンショット 2023-06-02 16.21.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/6a156734-be10-eae0-7179-c87ebde45453.png)

<br>

**■例文（カラーレンジ）**

```vuejs
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <br />
  <div :style="{ backgroundColor: changeColor }">
    <form v-for="o in colors" :key="o.id">
      <input type="range" v-model="o.status" min="0" max="255" />{{ o.color }}
    </form>
    <p>{{ changeColor }}</p>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      myText: "",
      colors: [
        { id: 1, color: "red", status: 255 },
        { id: 2, color: "blue", status: 255 },
        { id: 3, color: "green", status: 255 },
      ],
    };
  },
  computed: {
    textLength() {
      return this.myText.length;
    },
    changeColor() {
      return `rgb(${this.colors[0].status},${this.colors[1].status},${this.colors[2].status})`;
    },
  },
};
</script>
```

<br>

■ 結果
レンジを動かせば背景色が変化する。

![スクリーンショット 2023-06-02 17.51.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/e31d7714-93ab-9196-d778-aec975fb7b71.png)

<br>

![スクリーンショット 2023-06-02 17.52.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/34e087e2-08be-b80e-7311-c31addfbc5da.png)




## ◎ メリット

computedの１番のメリットとしては、複雑な処理を簡潔に書くことができる点。
これはマスタッシュを利用してデータをそのまま表示する場合だとイメージがしやすい。

**■例文（入力した文字の文字列を表示する。）**

```vuejs
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <br />
  <input type="text" v-model="myText" />
  <p>マスタッシュ：{{ myText.length }}</p>
  <p>算出プロパティ：{{ textLength }}</p>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      myText: "",
    };
  },
  computed: {
    textLength() {
      return this.myText.length;
    },
  },
};
</script>
```
上記のようにcomputedを利用すると、処理をする側と画面表示する側で綺麗に処理を分担できるので、簡潔で綺麗なコードが書けるようになる。

<br>

## ◎ メソッドとの違い

computedではなく、methodを使用するのとは何が違うのか。その違いは以下の通り。
これを考慮しないのであれば、methodを使用してもcomputedを使用しても変わりはない。

**■ computed**
→キャッシュの値を参照するため、リロードしてもデータが変わらない限りは表示に変化はない。

**■ method**
→キャッシュ機能がないため、たとえデータが変更されていない場合でも、ページをリロードする度に新しく実行される。

<br>
<br>

# ◆ watch（監視プロパティ）とは

データや変数の値が変わったときに何らかの処理を実行したいときに利用するオプション。
タイマーなどの`非同期処理`を用いて自動的に変化する値を監視するときに利用する。
<br>
**■構文**
```vuejs
<script>
data() {
    data1: "",
    data2: "",
    data3: "",
},
watch: {
    監視対象にしたいdata名（例：data1）{
        // data1が変化したときに実行したい処理内容
    }
}
</script>
```
<br>

**■例文（禁止文字を入力したらアラートを発生し、入力した禁止文字を削除）**

```vue
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <br />
  <p>禁止文字は「{{ forbiddenText }}」</p>
  <textarea v-model="inputText"></textarea>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      forbiddenText: "嫌い",
      inputText: "",
    };
  },
  computed: {},
  watch: {
    inputText() {
      let pos = this.inputText.indexOf(this.forbiddenText);
      if (pos === -1) {
        return "";
      } else {
        this.inputText = this.inputText.substr(0, pos);
        alert(`${this.forbiddenText} は入力できません。`);
      }
    },
  },
};
</script>
```
<br>

**■例文（タイマー）**

```vue
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <br />
  <input type="number" v-model="restSec" />
  <button v-on:click.enter="timerStart()">タイマースタート</button>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      restSec: 10,
      timerObj: null,
    };
  },
  methods: {
    timerStart() {
      this.timerObj = setInterval(() => {
        this.restSec--;
      }, 1000);
    },
  },
  computed: {},
  watch: {
    restSec() {
      if (this.restSec <= 0) {
        clearInterval(this.timerObj);
        alert("制限時間です");
      }
    },
  },
};
</script>
```
<br>
<br>

# ◆ 表示・非表示時にアニメーションする

「ある画面から別の画面に切り替わること」を`トランジション`といい、
切り替わる時のアニメーションのことを`トランジションアニメーション`という。

## ◎ Tansitionタグで囲う。

対象のHTML要素をTransitionrタグで囲うことで、その要素が現れたり消えたりするときにトランジションアニメーションをつけることができる。

■Vue構文
```vue
<Transition>
    <!-- 対象のHTML要素 -->
</Transition>
```

さらにTransitionでは、HTML要素の状態に応じてCSSを設定する必要がある。
これにより、アニメーションを発生させる。

■CSS構文
```css
/* 要素が現れる前の状態 */
.v-enter-from {}

/* 要素が現れている最中 */
.v-enter-active {}

/* 要素が現れた時の状態 */
.v-enter-to {}

/* 要素が消える前の状態 */
.v-leave-from {}

/* 要素が消えている最中 */
.v-leave-active {}

/* 要素が消えた時の状態 */
.v-leave-to {}

/* 要素が移動するとき */
.v-move {}
```

**公式ドキュメントより（各状態のイメージ図）**

![スクリーンショット 2023-06-10 17.33.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/79c7027b-bb8e-1e2f-f8c2-93fc7106abdb.png)

■例文

```vue
<template>
  <input type="checkbox" v-model="isOK" />切り替える
  <Transition>
    <!--チェックボックスにチェックをつける or 外すと、文字が下からフェードイン・フェードアウトする-->
    <div v-if="isOK">{{ isOK }}</div>
  </Transition>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      isOK: false,
    };
  },
};
</script>

<style>
.v-enter-active,
.v-leave-active {
  transition: 0.5s;
}

.v-enter-from,
.v-leave-to {
  opacity: 0;
  transform: translateY(20px);
}
</style>

```

<br>

## ◎ Tansition-groupタグを使用して、リストを管理
リストの数が増減したり、位置が移動する際にアニメーションをつけることができる。

■Vue構文

```vue
<TransitionGroup name="transition名" tag="リストを囲む親のタグを指定">
    <!-- 対象のHTML要素 -->
</TransitionGroup>

 <!-- ※nameとtag属性がないとTransitionが効かない（？） -->
```

■CSS構文

```css
/* 要素が現れる前の状態 */
.list-enter-from {}

/* 要素が現れている最中 */
.list-enter-active {}

/* 要素が現れた時の状態 */
.list-enter-to {}

/* 要素が消える前の状態 */
.list-leave-from {}

/* 要素が消えている最中 */
.list-leave-active {}

/* 要素が消えた時の状態 */
.list-leave-to {}

/* 要素が移動するとき */
.list-move {}
```


■例文

```vue
<template>
  <TransitionGroup tag="ul" name="list">
    
    <li v-for="item in items" :key="item">{{ item }}</li>
  </TransitionGroup>
<!--ボタンを押すと、追加したリスト・削除するリストが右からフェードイン・フェードアウトする-->
  <input type="text" v-model="addText" /><button @click="addList">追加</button>
  <button @click="deleteItem">最後の１行を削除</button>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      isOK: false,
      items: ["cake", "grape", "lemon", "cheese", "nuts"],
      addText: "",
    };
  },
  methods: {
    addList() {
      this.items.push(this.addText);
      this.addText = "";
    },
    deleteItem() {
      let lastIdex = this.items.length - 1;
      this.items.splice(lastIdex, 1);
    },
  },
};
</script>

<style>
.list-enter-active,
.list-leave-active {
  transition: 0.5s;
}

.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateX(50px);
}
</style>
```

<br>

### ◎ リストが移動した時のトランジションアニメーションを付与する。

■例文

```vue
<template>

  <TransitionGroup tag="ul" name="list">
    <li v-for="item in items" :key="item">{{ item }}</li>
  </TransitionGroup>
  <input type="text" v-model="addText" />

  <br /><button @click="addList">追加</button><button @click="deleteItem">最後の１行を削除</button> 
 <br /><button　@click="listSort">ソート</button><button @click="listSuffle">シャッフル</button>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      isOK: false,
      items: ["cake", "grape", "lemon", "cheese", "nuts"],
      addText: "",
    };
  },
  methods: {
    addList() {
      this.items.push(this.addText);
      this.addText = "";
    },
    deleteItem() {
      let lastIdex = this.items.length - 1;
      this.items.splice(lastIdex, 1);
    },
    listSort() {
      this.items.sort((a, b) => {
        if (a < b) {
          return -1;
        } else if (a > b) {
          return 1;
        } else {
          return 0;
        }
      });
    },
    listSuffle() {
      let newArray = [];
      let roop = this.items.length;
      for (let i = 0; i < roop; i++) {
        let index = Math.floor(Math.random() * this.items.length);
        newArray.push(this.items[index]);
        this.items.splice(index, 1);
      }

      this.items = newArray;
    },
  },
};
</script>

<style>
.list-enter-active,
.list-leave-active {
  transition: 0.5s;
}

.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateX(50px);
}

.list-move {
  transition: 0.5s;
}
</style>

```
<br>
<br>

# ◆ 部品で分ける（コンポーネント）

`コンポーネント`とは、UIの一部を再利用可能な部品として独立させる機能のこと。

コンポーネントには２種類あり、`グローバルコンポーネント`と`ローカルコンポーネント`がある。

## ◎ グローバルコンポーネント

■構文

簡単なコンポーネント用ファイルを用意。

**GlobalButton.vue**
```vue
<template>
  <button>グローバルコンポーネントボタン</button>
</template>

<script>
export default {
  name: "gButton",
};
</script>
```

**main.js**

```javascript
import { createApp } from "vue";
import App from "./App.vue";
import GlobalButton from "./components/GlobalButton";

createApp(App)
.component("GButton", GlobalButton)  // 追加
.mount("#app");
```

**App.vue**

```vue
<template>
  <GButton />
</template>
```
<br>
<br>

## ◎ ローカルコンポーネント

■構文

簡単なコンポーネント用ファイルを用意。

**Button.vue**
```vue
<template>
  <button>コンポーネントボタン</button>
</template>

<script>
export default {
  name: "Button",
};
</script>
```

**App.vue**

```vue
<template>
  <Button />
</template>

<script>
// importする
import Button from "./components/Button.vue";
export default {
  name: "App",
  // コンポーネントオプションに設定
  components: {
 // プロパティ名　：　コンポーネント名（プロパティ名とコンポーネント名が同名の場合は以下のように省略可能）
    Button,
  },
};
</script>
```
<br>
<br>

## ◎ プロパティの受け渡しはPropsを使用

■構文

**Button.vue**
```vue
<template>
  <button>コンポーネントボタン{{ title }}</button>
</template>

<script>
export default {
  name: "Button",

 // 文字列の配列で宣言
  props: ["title"],

 // もしくは、オブジェクト構文で宣言（この場合は、プロパティ名：型　で宣言する。）
  props: {
    title: String,
    age: number,
  }
};
</script>
```

**App.vue**

```vue
<template>
   <!-- propsでプロパティを受け渡し -->
  <Button title="HELLO !!" />
</template>

<script>
import Button from "./components/Button.vue";
export default {
  name: "App",
  components: {
    Button,
  },
};
</script>
```

**結果**
![スクリーンショット 2023-06-11 1.17.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/6bda69b0-ec53-7ca7-1fa3-b089236b21ff.png)

<br>

以下のように親コンポーネントから配列やオブジェクトでpropsを設定することも可能。
<br>
ここで注目するべきところは、今回のように`動的なプロパティ値をpropsに渡す場合、`
`v-bind（今回でいう:title）`を使用するということ。

```vue
<template>
  <Button v-for="item in propsArray" :key="item.id" :title="item.title" />
</template>

<script>
import Button from "./components/Button.vue";
export default {
  name: "App",
  data() {
    return {
      propsArray: [
        { id: 1, title: "Javascript" },
        { id: 2, title: "Java" },
        { id: 3, title: "PHP" },
        { id: 4, title: "React" },
        { id: 5, title: "Vue.js" },
      ],
    };
  },
  components: {
    Button,
  },
};
</script>
```