連動するプルダウンリストを作ったので、Vueを使ってコンポーネント化してみた

こんにちは皆さん

[前回](https://qiita.com/niisan-tokyo/items/7d15716304c492f244c2)、連動して内容が変わるプルダウンリストをVueを使って実装してみました。
ちょうどいい素材なので、こいつを使ってVueを使ったコンポーネント化の練習でもしようかなって思いました。

練習とかいいからって人は、完成形のところまで飛ばしてくれればいいんじゃないかな。

# 早速実装

[前回の記事を前提にしているので、みてない人は見てね](https://qiita.com/niisan-tokyo/items/7d15716304c492f244c2)

## テンプレート化
連動する部分をコンポーネント化するので、該当箇所は次の部分になります。

```html
<div class="row">
     <div class="col-3 offset-1 form-group">
        <select class="form-control" v-model="selected">
            <option v-for="parent in parents">
                {{ parent }}
            </option>
        </select>
    </div>
    <div class="col-3 form-group">
        <select class="form-control" >
            <option v-for="child in children">
                {{ child }}
            </option>
        </select>
    </div>
</div>
```
こいつをテンプレートにしてみます。

```js
Vue.component('my-coodinate-list', {
    template: '<div class="row">\
         <div class="col-3 offset-1 form-group">\
            <select class="form-control" v-model="selected">\
                <option v-for="parent in parents">\
                    {{ parent }}\
                </option>\
            </select>\
        </div>\
        <div class="col-3 form-group">\
            <select class="form-control" >\
                <option v-for="child in children">\
                    {{ child }}\
                </option>\
            </select>\
        </div>\
    </div>'
})
```
こんな感じですね

## propsの定義
この中で、外部から渡されるべき変数は`parents`および各親要素に対応する子要素のリスト`children_group`となりますので、propsを以下のように定義できます。

```js
Vue.component('my-coodinate-list', {
    props: ['parents', 'children_group'],
    template: (略)
})
```
となります。

## dataとcomputed
コンポーネントの中でまだ定義されていない変数が`selected`と`children`です。`selected`は初期値の設定が必要で、`children`はselectedの値から動的にリストを選ぶので、それぞれdata, computedに定義してやります。

```js
Vue.component('my-coodinate-list', {
    props: ['parents', 'children_group'],
    data: function () {
        return {
            selected: ''
        }
    },
    computed: {
        children: function () {
            return this.children_group[this.selected]
        }
    },
    template: (略)
})
```

# 完成形
というわけで、あとはベタッと展開されていた二つのセレクトボックス項を一個にまとめるだけです。

```coodinate.php
<?php
$data = [
    'A' => ['A1', 'A2', 'A3'],
    'B' => ['B1', 'B2', 'B3'],
    'C' => ['C1', 'C2', 'C3']
];
$number = 4;
?>
<html>
<header>
    <meta charset="utf-8">
    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-WskhaSGFgHYWDcbwN70/dfYBj47jz9qbsMId/iRN3ewGhXQFZCSftd1LZCfmhktB" crossorigin="anonymous">
</header>
<body>
<div id="app">
    <div class="row">
        <div class="offset-1">
            <h2>連動プルダウン</h2>
        </div>
    </div>
    <?php for ($i = 0; $i < $number; $i++) { ?>
    <div class="row">
    <div class="offset-1">
        <h3><?php echo $i + 1 ?>番目</h3>
    </div>
    </div>
    <my-coodinate-list v-bind:parents="parents" v-bind:children_group="children_group"></my-coodinate-list>
    <?php }?>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script>
var children_group = <?php echo json_encode($data); ?>;
var parents = Object.keys(children_group)

// 連動リストコンポーネント
Vue.component('my-coodinate-list', {
    props: ['parents', 'children_group'],
    data: function () {
        return {
            selected: ''
        }
    },
    computed: {
        children: function () {
            return this.children_group[this.selected]
        }
    },
    template: '<div class="row">\
         <div class="col-3 offset-1 form-group">\
            <select class="form-control" v-model="selected">\
                <option v-for="parent in parents">\
                    {{ parent }}\
                </option>\
            </select>\
        </div>\
        <div class="col-3 form-group">\
            <select class="form-control" >\
                <option v-for="child in children">\
                    {{ child }}\
                </option>\
            </select>\
        </div>\
    </div>'
})

var app = new Vue({
    el: '#app',
    data: {
        parents: parents,
        children_group: children_group
    }
})
</script>
</body>
</html>
```
JSの部分が太りましたが、htmlの部分がスッキリしているのがわかるかと思います。

毎度のことであれですが、PHPアレルギーの人はjson部分とかを適宜読み替えてください。
こいつをサーバに置くなり、PHPのビルトインサーバで動かす ( 詳細は前回参照 )なりすると、

![連動プルダウン](https://camo.qiitausercontent.com/a91b5cdc73c2b08f198b13c50d4dd1ce795b6d50/68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3130323138322f38666361363364362d386631322d303930662d303132622d3336356465313036626133342e6a706567)

こんな感じの連動プルダウンリストが作れます。

# まとめ

ということで、前回作った連動プルダウンリストのVueコンポーネントを実装してみました。
単純に該当箇所を切り取った後に、外から注入される部分、初期値だけ必要なやつ、動的処理が必要なやつに切り分けて実装するだけなので、わりとあっさりできる印象です。
ソースコード見ると前回よりもちょい太っていますが、こいつを色んな所で使いまわせるんなら、その程度のコストを払っても安いという感じでしょうかね。

短いですが、今回はこんなところです。