📚

【Nuxt.js】カスタムセレクトフォームを作ってみた

2020/11/28に公開

背景

こんにちは、ユウです。
仕事上でselectフォームを使うことになり、でもぐぐってみたら大体の記事はselectフォームにv-modelで初期値を設定してます。
今回はselectフォームのコンポーネントを作成するのが要件で、かつ開発規約上コンポーネントにはdataを持たせないです。そうなるとv-modelは機能できませんし、propsの値もv-modelに指定できないから八方塞がりの状態に...

こうなると、v-modelを使わずにselectフォームのコンポーネントを作るしかないです。

仕様

今回作成するselectコンポーネントの仕様は下記です。

  1. コンポーネントにdataを持たせない。(これは独自ルールです、実際このルールがなければv-modelでことが足りるでしょう)
  2. propsでselectの初期値を指定できる。
  3. selectフォームの横に表示する文字はslotで指定できる。
  4. selectフォームでの操作処理はemitで親コンポーネントに任す。

3に関してはこういうことです。

親コンポーネントコード

ではまず親コンポーネントから呼び出すコードを見ましょう。

<SelectBox
  :id="`min-number`"
  :value="defaultMinNumber"
  :options="options"
  @selected="selected"
  ></SelectBox>
<SelectBox
  :id="`max-number`"
  :value="defaultMaxNumber"
  :options="options"
  @selected="selected"
/>

export default {
  data() {
    return {
      defaultMinNumber: '1',
      defaultMaxNumber: '5',
      options: [
        { code: '1', name: '1名' },
        { code: '2', name: '2名' },
        { code: '3', name: '3名' },
        { code: '4', name: '4名' },
        { code: '5', name: '5名' },
      ],
    };
  },
  methods: {
    selected(value, id) {
      // ここで処理select操作後の処理を書く
      // idは操作したselectフォームのid、valueは選択した値です
    }
  }
}

selectコンポーネントに渡すpropsを説明します。
id : 操作したselectフォームはどれなのか特定するため用のidです。これは親コンポーネントがフォーム操作後の処理に使えます。
value : selectフォームの初期値です。optionsのcodeに一致する値があればそれが初期値として設定されます。
options : フォームの選択肢です。codeは選択肢の値で、nameは表示用の文字列です。
selected : selectコンポーネントからemitで呼び出されて、選択操作後の処理用のmethodを呼び出す。

selectコンポーネントのコード

<template>
  <span>
    <select :value="value" @input="selected">
      <option v-for="option in options" :key="option.code" :value="option.code">
        {{ option.name }}
      </option> </select
    ><span class="slot-text"><slot></slot></span>
  </span>
</template>


<script>
export default {
  props: {
    id: {
      type: String,
      default: '',
    },
    value: {
      type: String,
      default: '',
      required: true,
    },
    options: {
      type: Array,
      required: true,
    },
  },
  methods: {
    selected($event) {
      this.$emit('selected', $event.target.value, this.id);
    },
  },
};
</script>

v-modelなしで初期値を指定するため、:value="value"でpropsに渡される値を設定する。
注意点としてはイベントは@inputで設定してあること、@changeではありません。
どこかの記事で@changeではうまく動作しない可能性があるから@inputのほうが無難でしょう。

親に値を渡すため、みんな大好きemitを使って、選択されたvalueと操作したselectフォームのidを渡してます。
あとは親コンポーネントで適宜に処理すればOKです。

最後に

独自ルールがあるから色々とselectフォームの実装について調べました。v-selectというものを使えばもっと楽に実装できますが、保守や拡張性を考えるとやはり自前で実装した方が良いですね。

かなりマイナーの内容でしたが、最後まで読んで頂きありがとうございます。
それではまだ。

Discussion