【Vue × Firestore】検索機能の実装

#検索機能の実装

###search.vue(子コンポーネント)

```html
 <template>
  <div class="search-inner flex">
    <h2 class="search-tll neon flex">Cinemaryを検索する</h2>
    <hr class="separate" />
    <div class="search-main-contens flex">
      <input
        placeholder="例）アクション 恋愛 ミステリー SF ホラー ミュージカル etc.."
        class="search-main-item"
        type="search"
        v-model="inputValue"
      />
    </div>
  </div>
</template>
```

```javascript
<script>
export default {
  data() {
    return {};
  },
  props: {
    value: {
      type: String,
      required: true
      //文字列型を必須で要求する
    }
  },
  computed: {
    inputValue: {
      get() {
        return this.value;
        //getterとは、変数から値を取得して呼び出し元に返す関数。ここではpropsで親より受けた値(value)を返している。
      },
      set(value) {
        this.$emit("input", value);
        //setterとは、変数に値(value)を設定する関数。ここでは入力フォーム(input)に入力された値(value)を返している。
      }
    }
  }
};
</script>
```



まず以下記事を参考に親子間のコンポーネントのデータ伝播を実装していきます。

https://qiita.com/toshifumiimanishi/items/07c8e96eb6f8e50c5e27




###board.vue(親コンポーネント)

```html
<template>
  <div>
    <Header />
       <Search v-model="searchWord" />
    <Post />
    <div class="post">
      <h2 id="top" class="post-tll neon">投稿一覧</h2>
      <div class="post-inner">
        <div class="post-items">
          <paginate
            name="paginate-log"
            tag="ol"
            :list="filteredPostData"
            :per="12"
            v-if="filteredPostData.length !== 0"
          >
          <!-- filteredPostDataにて該当する投稿がある場合、表示。 -->
            <List
              v-for="(list, index) in paginated('paginate-log')"
              :index="index"
              :list="list"
              :userDatas="userDatas"
              :key="list.id"
            />
          </paginate>
          <div v-else class="nothing">" {{searchWord}} " に該当する投稿はありませんでした。</div>
          <!-- filteredPostDataにて該当する投稿がない場合、上記を表示させる。 -->
          <paginate-links
            for="paginate-log"
            class="pagination flex"
            v-scroll-to="postTop"
            :show-step-links="true"
            :style="filteredPostData.length !== 0 == '' ? 'display:none;' : 'display:flex;'"
          ></paginate-links>
        </div>
      </div>
    </div>
  </div>
</template>
```

```javascript

export default {
  data() {
    return {
      searchWord: ""
    };
  },
  components: {
    List,
    Search
  },
  computed: {
    filteredPostData() {
      if (this.searchWord != "") {
        return this.postData.filter(v => {
          return ~v.genre.indexOf(this.searchWord);
          //検索内容(this.searchWord)と同じ内容(genre)を持つ要素の位置を返す。存在しない場合、-1を返す。
          //しかし、-1は今回ない為、「~v」とビット反転演算子(符号を反転してマイナス1した数)を使って、-1 → 0となる。
        });
      } else {
        return this.postData;
        //サーチ内容がない場合はそのまま、それ以外はフィルタ結果を返す
      }
    }
  },
  created() {
    firebase
      .firestore()
      .collection("posts")
      .orderBy("time", "desc")
      .get()
      .then(snapshot => {
        snapshot.forEach(doc => {
          this.postData.push({ ...doc.data(), id: doc.id });
        });
      });
  }
};
</script>
```

search.vue(子コンポーネント)から受けたデータをもとにfilteredPostData()メソッドを使って
今回はgenreのデータで条件を絞って表示しております。