【Vue】絞り込み検索を作る

Vueを使ったWEBアプリで絞り込み検索を作りました。

GitHubはこちら

https://github.com/buuibuui/SEVENTEEN-visited-map

# 💎 概要
+ 条件を選択する検索バーcomponentと場所データを管理するstore.jsでやりとりをし、表示する場所データリストを変更する。
+ 検索バーcomponentでは、条件をstoreに伝えるだけでデータリストの操作に関与しない。

### 画面
絞り込み検索前
![絞り込み検索前](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178942/7673efe0-c8ff-d907-386c-8906df47ce95.png)
絞り込み検索後
![絞り込み検索後](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1178942/61007777-428c-a3f7-ee0d-8967ee63beb5.png)
### 環境
+ vue(2.6.14)
+ vuex(3.6.2)
+ vuetify(2.6.0)
# 💎 コード
### 検索バーのcomponent
```vuejs:FilteringBarComp.vue
<template>
    <v-form
        ref="form"
        class="form-container d-flex flex-column flex-md-row justify-md-space-between"
    >
        <div class="d-flex">
            <v-select
                class="select-area mx-2"
                v-model="selectedArea"
                :items="area"
                item-text="label"
                item_value="value"
                label="AREA"
                hint="エリアを選んでください"
                persistent-hint
            ></v-select>
            <v-select
                class="select-category mx-2"
                v-model="selectedCategory"
                :items="category"
                item-text="label"
                item_value="value"
                label="CATEGORY"
                hint="施設の種類を選んでください"
                persistent-hint
            ></v-select>
            <v-select
                class="select-member mx-2"
                v-model="selectedMember"
                :items="members"
                label="MEMBER"
                hint="メンバーを選んでください"
                persistent-hint
            ></v-select>
        </div>

        <div class="d-flex align-center">
            <v-btn
            outlined
            color="white"
            @click="filterPlaceList()"
            >絞り込む</v-btn>

            <v-btn
            class="ml-2"
            outlined
            color="white"
            @click="resetPlacesList()"
            >リセット</v-btn>

            <div
            class="result-text mx-3"
            >検索結果：{{ $store.state.displayingPlaceList.length }}件
            </div>
        </div>
    </v-form>
</template>

<script>

export default {
    data: () => ({
        // 絞り込み検索の項目リスト（メンバー）
        members: [
            "S.Coups",
            "Jeonghan",
            "Joshua",
            "Jun",
            "Hoshi",
            "Wonwoo",
            "Woozi",
            "The8",
            "Mingyu",
            "Dokyeom",
            "Seungkwan",
            "Vernon",
            "Dino"
        ],
        // 絞り込み検索の項目リスト（場所）
        area: [
            { label: "東京エリア", value: "tokyo" },
            { label: "大阪エリア", value: "osaka" },
            { label: "名古屋エリア", value: "nagoya" }
        ],
        // 絞り込み検索の項目リスト（施設分類）
        category: [
            { label: "道端", value: "roadside" },
            { label: "飲食店", value: "restaurant" },
            { label: "美術館", value: "museum" },
            { label: "公園", value: "park" },
            { label: "山", value: "mountain" },
            { label: "その他店", value: "others" },
        ],
        filteredList: [],
        selectedArea: null,
        selectedCategory: null,  
        selectedMember: null,
    }),
    computed: {
        placeList() { return this.$store.state.placeList },
    },
    methods: {
        // storeのexcuteFilter関数を呼び出す関数
        // 選択された条件は複数存在するのでオブジェクトで渡す
        filterPlaceList() {
            this.$store.dispatch('executeFilter', {
                area: this.selectedArea,
                category: this.selectedCategory,
                member: this.selectedMember
            })
        },
        // 絞り込み検索の条件をリセットする関数
        resetPlacesList() {
            this.$refs.form.reset();
            this.$store.commit('resetFilter');
        }
    }
}
</script>
```
### store.js
```javascript:store.js(関係部分のみ)
export default new Vuex.Store({
    state: {
        // 全ての場所データリストJSON
        placeList: placeList,
        // 表示する場所データリスト(default: placeList)
        displayingPlaceList: placeList,
    },
    getters: {
        // 絞り込みfilter(エリア)
        filterOfArea: (state) => (area) => {
            if (area == "tokyo") {
                return state.placeList.filter(place => place.id > 1000 && place.id < 1999);
            } else if (area == "osaka") {
                return state.placeList.filter(place => place.id > 2000 && place.id < 2999);
            } else if (area == "nagoya") {
                return state.placeList.filter(place => place.id > 3000 && place.id < 3999);
            }
        },
        // 絞り込みfilter(カテゴリー)
        filterOfCategory: (state) => (category) => {
            return state.placeList.filter(item => item.placeCategory == category);
        },
        // 絞り込みfilter(メンバー)
        filterOfMember: (state) => (member) => {
            return state.placeList.filter(item => item.members.includes(member));
        }
    },
    mutations: {
        // 絞り込み後の場所データリストを反映させる関数
        // 引数listで絞り込み後のデータリストを受け取り、displayingPlaceListに代入
        setFilteredList(state, list) {
            state.displayingPlaceList = list;
        },
        // 絞り込み検索のリセット関数
        resetFilter(state) {
            state.displayingPlaceList = state.placeList;
        }
    },
    actions: {
        // 絞り込み検索を行う本体関数
        // 選択された条件がある場合、filterに通す
        executeFilter({ commit }, { area, category, member }) {
            let resultArr = this.state.placeList;
    
            // もし条件が選択されている場合（引数でもらったオブジェクトに値がある場合）、filterを実行する
            if (area != null) {
               const resultAreaArr = this.getters.filterOfArea(area);
               resultArr = resultArr.filter(item => resultAreaArr.includes(item));
            }
            if (category != null) {
               const resultCategoryArr = this.getters.filterOfCategory(category);
               resultArr = resultArr.filter(item => resultCategoryArr.includes(item));
            }
            if (member != null) {
               const resultMemberArr = this.getters.filterOfMember(member);
               resultArr = resultArr.filter(item => resultMemberArr.includes(item));
            }
            commit('setFilteredList', resultArr);
     },
  }
})
```
# 💎 思ったこと
+ storeにこんなに関数を入れていいのか？