今回は、自作したプロ野球の投手VS野手の対戦成績検索画面を例に、Vue.jsでのvue-multiselectの導入方法と活用法を紹介します。
完成したアプリは以下のリンクからご覧いただけます。
このアプリでは、投手名や野手名を選択する際にvue-multiselectを使用しています。この記事では、実際の画面も交えながら、vue-multiselectの使い方を詳しく解説します。
操作動画
実際にイメージしやすいよう、はじめに操作動画を載せておきます。
目次
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;
},
},
};
具体的な流れ
- ユーザー入力: ユーザーが検索ボックスに文字を入力すると、@search-changeイベントが発火し、対応するupdatePitcherSearchまたはupdateBatterSearchメソッドが呼び出され、検索クエリが更新されます。
- リストのフィルタリング: 検索クエリが更新されると、filteredPitcherListまたはfilteredBatterListが再評価されます。
- 正規化と比較:
• 検索クエリと選手名(漢字・カナ)の両方からスペースを削除します。
• 正規化された文字列同士でincludesを用いて部分一致を確認します。 - 結果の表示: フィルタリングされたリストが画面上に表示され、ユーザーは選択肢から目的の選手を選べます。
スロットのカスタマイズ
データが存在しない場合の表示を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を使った実装例と活用法の紹介でした。ご質問やフィードバックがありましたら、コメント欄でお知らせください。