0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Vue.jsでvue-multiselectを使用する方法

Posted at

今回は、自作したプロ野球の投手VS野手の対戦成績検索画面を例に、Vue.jsでのvue-multiselectの導入方法と活用法を紹介します。

完成したアプリは以下のリンクからご覧いただけます。

プロ野球|投手 vs 野手 対戦成績検索

このアプリでは、投手名や野手名を選択する際にvue-multiselectを使用しています。この記事では、実際の画面も交えながら、vue-multiselectの使い方を詳しく解説します。

操作動画

実際にイメージしやすいよう、はじめに操作動画を載せておきます。

動画:投手と野手を選択して対戦成績を検索するデモ
プルダウン.gif

目次

vue-multiselectの導入

インストール

まず、vue-multiselectをプロジェクトにインストールします。

# npmの場合
npm install vue-multiselect

# yarnの場合
yarn add vue-multiselect

コンポーネントの登録

使用するVueコンポーネントでvue-multiselectをインポートし、登録します。

import Multiselect from 'vue-multiselect';

export default {
  components: {
    Multiselect,
  },
  // その他のオプション
};

スタイルのインポート

vue-multiselectのスタイルシートもインポートします。これはコンポーネント内で以下のように記述します。

<style src="vue-multiselect/dist/vue-multiselect.min.css"></style>

実装例とオプションの解説

投手名と野手名の選択

以下は、投手名と野手名を選択するためのmultiselectコンポーネントの実装例です。

<template>
  <div>
    <!-- 投手名選択 -->
    <multiselect
      v-model="selectPitcherOptions"
      :options="filteredPitcherList"
      label="playerNm"
      track-by="playerId"
      placeholder="選手名を入力で絞り込み可能"
      :select-label="'選択'"
      :deselect-label="'解除'"
      @search-change="updatePitcherSearch"
      :filterable="false"
      :internal-search="false"
    >
      <template slot="noResult">
        <span>対象データがありません</span>
      </template>
    </multiselect>

    <!-- 野手名選択 -->
    <multiselect
      v-model="selectBatterOptions"
      :options="filteredBatterList"
      label="playerNm"
      track-by="playerId"
      placeholder="選手名を入力で絞り込み可能"
      :select-label="'選択'"
      :deselect-label="'解除'"
      @search-change="updateBatterSearch"
      :filterable="false"
      :internal-search="false"
    >
      <template slot="noResult">
        <span>対象データがありません</span>
      </template>
    </multiselect>
  </div>
</template>

主要なオプションの説明

  • v-model: 選択された値をバインドします。
  • :options: プルダウンに表示するオプションリストです。
  • label: オプションの表示に使用するプロパティ名(ここではplayerNm)。
  • track-by: オプションの一意性を識別するプロパティ名(ここではplayerId)。
  • placeholder: 未選択時に表示されるテキスト。
  • :select-label: オプション選択時のラベルをカスタマイズ。
  • :deselect-label: オプション解除時のラベルをカスタマイズ。
  • @search-change: ユーザーが検索入力を変更した際に発火するイベント。
  • :filterable="false": 内部のフィルタリング機能を無効化。
  • :internal-search="false": 内部検索を無効にし、カスタム検索を実装。
    ※今回はひらがな・漢字どちらの検索にも対応させ、尚且つ空白を許容したかったため、既存のフィルタリング機能や内部検索を無効化しました。

カスタム検索の実装

@search-changeイベントを使用して、ユーザーの入力に基づいたカスタム検索を実装します。
主な目的は、ユーザーが投手や野手を検索する際に、漢字やひらがな、スペースの有無を気にせずに直感的に入力できるよう工夫しています。

export default {
  data() {
    return {
      selectPitcherOptions: null,
      selectBatterOptions: null,
      searchQueryPitcher: '',
      searchQueryBatter: '',
      localPitcherList: [], // 投手リスト
      localBatterList: [],  // 野手リスト
    };
  },
  computed: {
    filteredPitcherList() {
      if (!this.searchQueryPitcher) {
        return this.localPitcherList;
      }
      const query = this.searchQueryPitcher.toLowerCase().replace(/[\s\u3000]/g, '');
      return this.localPitcherList.filter(player => {
        const name = player.playerNm.toLowerCase().replace(/[\s\u3000]/g, '');
        const kana = player.playerNmKana.toLowerCase().replace(/[\s\u3000]/g, '');
        return name.includes(query) || kana.includes(query);
      });
    },
    filteredBatterList() {
      if (!this.searchQueryBatter) {
        return this.localBatterList;
      }
      const query = this.searchQueryBatter.toLowerCase().replace(/[\s\u3000]/g, '');
      return this.localBatterList.filter(player => {
        const name = player.playerNm.toLowerCase().replace(/[\s\u3000]/g, '');
        const kana = player.playerNmKana.toLowerCase().replace(/[\s\u3000]/g, '');
        return name.includes(query) || kana.includes(query);
      });
    },
  },
  methods: {
    updatePitcherSearch(query) {
      this.searchQueryPitcher = query;
    },
    updateBatterSearch(query) {
      this.searchQueryBatter = query;
    },
  },
};

具体的な流れ

  1. ユーザー入力: ユーザーが検索ボックスに文字を入力すると、@search-changeイベントが発火し、対応するupdatePitcherSearchまたはupdateBatterSearchメソッドが呼び出され、検索クエリが更新されます。
  2. リストのフィルタリング: 検索クエリが更新されると、filteredPitcherListまたはfilteredBatterListが再評価されます。
  3. 正規化と比較:
    • 検索クエリと選手名(漢字・カナ)の両方からスペースを削除します。
    • 正規化された文字列同士でincludesを用いて部分一致を確認します。
  4. 結果の表示: フィルタリングされたリストが画面上に表示され、ユーザーは選択肢から目的の選手を選べます。

スロットのカスタマイズ

データが存在しない場合の表示をnoResultスロットでカスタマイズしています。

<template slot="noResult">
  <span>対象データがありません</span>
</template>

その他の便利なオプション

vue-multiselectには他にも便利なオプションが多数あります。以下にいくつか紹介します。

複数選択を可能にする

multipleオプションを使用すると、複数のオプションを選択できます。

<multiselect
  v-model="selectedOptions"
  :options="options"
  :multiple="true"
  placeholder="複数のオプションを選択可能"
></multiselect>

タグの追加を許可する

ユーザーが独自のオプションを追加できるようにします。

<multiselect
  v-model="selectedTags"
  :options="tags"
  :multiple="true"
  :taggable="true"
  placeholder="タグを追加可能"
  @tag="addTag"
></multiselect>

methods: {
  addTag(newTag) {
    this.tags.push(newTag);
    this.selectedTags.push(newTag);
  },
},

オプションのグループ化

オプションをカテゴリー別にグループ化して表示します。

<multiselect
  v-model="selectedOption"
  :options="groupedOptions"
  :group-values="'items'"
  :group-label="'group'"
  placeholder="グループ化されたオプション"
></multiselect>

カスタムテンプレート

オプションの表示方法をカスタマイズできます。
例)「背番号 - 選手名」などの表示を実現

<multiselect
  v-model="selectedOption"
  :options="options"
  :custom-label="customLabel"
  placeholder="カスタムテンプレート"
>
  <template slot="option" slot-scope="{ option }">
    <div class="option__image">
      <img :src="option.image" alt="">
    </div>
    <div class="option__info">
      <span class="option__name">{{ option.name }}</span>
      <span class="option__desc">{{ option.description }}</span>
    </div>
  </template>
</multiselect>

methods: {
  customLabel(option) {
    return `${option.name} - ${option.description}`;
  },
},

まとめ

vue-multiselectを活用すると、ユーザーが使いやすい高度なセレクトボックスを簡単に実装できます。自作したプロ野球選手の対戦成績検索フォームを例に、導入方法や主要なオプションの使い方を紹介しました。
※Vue3では使用できない可能性が高いです。

参考リンク

以上、vue-multiselectを使った実装例と活用法の紹介でした。ご質問やフィードバックがありましたら、コメント欄でお知らせください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?