jQueryとVue.jsの比較（算出プロパティ編）


前回の「[jQueryとVue.jsの比較（入力バインディング編）](https://qiita.com/nori-shio88/items/7fc5eb5545292ed3e1ac)」に続いて、今回は算出プロパティ編です。

Vue.jsのドキュメントは以下にあります。

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

Vue.jsでは`v-if`や`v-for`などテンプレート内に計算式を持つことができます。
ただ持ちすぎるとテンプレートのメンテナンス性が低下するので、算出プロパティで外部に出して処理に名前をつけるようにします。この算出プロパティはテンプレート上、変数のように扱うことができます。

## 算出プロパティ
今回は以下のようなリストで選択された値に合わせて`<p>`タグ内の値を変更するようにしてみます。
### 画面

![スクリーンショット 2020-01-27 23.35.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26911/da17dc97-4aa2-4317-eff5-f43752de6960.png "スクリーンショット 2020-01-27 23.35.37.png")

![スクリーンショット 2020-01-27 23.36.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26911/f7837242-6103-13a2-187d-50700687fba5.png "スクリーンショット 2020-01-27 23.36.01.png")

### 今回の前提条件
リストの選択肢は配列で定義します。

```json:値
[
    {
        name: "綾波レイ",
        eva: "零号機",
        key: 0
    },
    {
        name: "碇シンジ",
        eva: "初号機",
        key: 1
    },
    {
        name: "惣流アスカラングレー",
        eva: "弐号機",
        key: 2
    }
]
```

## jQueryの場合
HTMLのBODY部分は以下の通りです。

```html
<div class="container">
	<div class="mt-5"></div>
	<div class="card">
	    <div class="card-header">
	        jQueryの場合
	    </div>
	    <div class="card-body">
	        <div class="form-group">
	            <select id="select"></select>
	        </div>
	        <h5 class="card-title">搭乗機</h5>
	        <p class="card-text" id="result1"></p>
	    </div>
	</div>
</div>
```

`<select id="select">`の部分に選択肢を追加します。
そして、初期選択状態は`{name: "綾波レイ",eva: "零号機",key: 0}`を選ばせた状態にします。
初期値を`<p>`タグに表示させたいので、このあと出てくる`#select`の`change`イベントを発火させてます。

```javascript
const eva = [{
    name: "綾波レイ",
    eva: "零号機",
    key: 0
},
{
    name: "碇シンジ",
    eva: "初号機",
    key: 1
},
{
    name: "惣流アスカラングレー",
    eva: "弐号機",
    key: 2
}
];

$(function () {
    // リストの追加
    for (item in eva) {
        $("#select").append($("<option>").val(eva[item].key).text(eva[item].name));
    }
    //初期値の設定
    $('#select').val(0);
    //イベントトリガーの強制発火
    $('#select').trigger('change');
});
```

リストの選択状態が変更されたのをトリガーに`<p>`タグ内の値を変更したいので

```javascript
$("#select").change(function () {
    var target = eva.filter(el => el.key === Number($(this).val()))[0].eva;
    $("#result1").html(target);
});
```

上記の様に、選択された値を取得し配列から対象の要素を`filter`で抜き出し、
`eva`の要素の値を` <p id="result1">`に埋め込んでます。

### 結果
以下の様にリストの選択で誰が選ばれたかによって、搭乗機が変更されるようになりました。

![jquery.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26911/9dcadc37-c852-22cc-782f-f638b0877083.gif "jquery.gif")

では、今回もVue.jsで同じ画面を作ってみたいと思います。

## Vue.jsの場合
HTMLのBODY部分は以下の通りです。

```html
<div class="container">
    <div class="mt-5"></div>
    <div class="card" id="vue">
        <div class="card-header">
            Vue.jsの場合
        </div>
        <div class="card-body">
            <div class="form-group">
                <select v-model="selected">
                    <option v-for="item in eva" :value="item.key">{{ item.name }}</option>
                </select>
            </div>
            <h5 class="card-title">搭乗機</h5>
            <p class="card-text" id="result2">{{ getEva }}</p>
        </div>
    </div>
</div>
```

- `<select v-model="selected">`と前回同様`v-model`で選択された値を双方向データバインディングとして定義
- `<option>`タグは`v-for="item in eva"`と`data`の値を回します
	- 回された際に中にある`item.key`を`<option>`の`value`に定義
	- 選択肢の表示用に`{{ item.name }}`と定義
- `<p>`タグ内に表示させる結果は`{{ getEva }}`で定義

では、javascipt側です。

```javascript
new Vue({
    el: "#vue",
    data: {
        selected: 0,
        eva: [{
                name: "綾波レイ",
                eva: "零号機",
                key: 0
            },
            {
                name: "碇シンジ",
                eva: "初号機",
                key: 1
            },
            {
                name: "惣流アスカラングレー",
                eva: "弐号機",
                key: 2
            }
        ]
    },
    computed: {
        getEva: function () {
            return this.eva.filter(el => el.key === this.selected)[0].eva;
        }
    }
});
```

- `data`にて`selected: 0`と初期値を固定で定義してます
- 前回出てこなかった`computed`がありますが、これが **算出プロパティ** です
	- `getEva`と画面に埋め込んでましたが算出プロパティ側で定義されてるものでした
	- 中身は`data`の`selected`と一致する`eva`の配列の`key`を見つけて`eva`を返却です

### 結果

![vue.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26911/73b85fad-e45d-f57c-257a-81262a22e01d.gif "vue.gif")


同じ動きのものが無事できました。

## おまけ
算出プロパティは個人的には中身に計算式を定義しておいて、dataなど周りで定義されてる値が変更されると同期的に計算式通りに値を書き換えてくれる。周りが変われば私も合わせますぞって素直な子のイメージ。
例えば消費税を計算するときの計算式は1.1掛けすればいいのでjavascriptだと

```javascript
Math.floor(入力された金額 * 1.1)
```
と書けて、それを算出プロパティに定義しておけばよいので

```html
<html>
<head>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <div id="vue">
        <p>税抜金額</p>
        <input type="number" v-model="excluded">
        <p>税込み価格</p>
        <p id="result2">{{ getTax }}</p>
    </div>
    <script>
        new Vue({
            el: "#vue",
            data: {
                excluded: 0
            },
            computed: {
                getTax: function () {
                    return Math.floor(this.excluded * 1.1);
                }
            }
        });
    </script>
</body>
</html>
```
とするだけで簡単に以下のようにできます。
![omake.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26911/113c14cc-55b4-a9ea-f14a-29560d546271.gif "omake.gif")

今回はここまでです。