3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

[Vue3 CompositionAPI]カンマ区切りのinputコンポーネントを作成する

Last updated at Posted at 2022-04-30

はじめに

この記事では、Vue3系でカンマ区切りで表示するinputコンポーネントを作成します。

使用技術

  • Vue3
  • CompositionAPI

作成するinputコンポーネントの要件

  1. 数値の入力のみを許容する
  2. コンポーネント利用側は値を数値型(null含む)として入力値を受け取れる
  3. blur時は1,234のようにカンマ区切りで値を表示する
  4. focus時は'1234'のように数値として値を表示する
  5. 以下のようにv-modelディレクティブを使用できる
<CommaInput v-model="hoge" />

成果物

CodeSandBoxでソースコードを書きました。
こちらで主題のinputコンポーネントの挙動を確認してみてください!
CodeSandBox上で書いたコード

実装

主題のinputコンポーネント

CommaInput.vue
<template>
  <input
    :value="commaSeparetedValue"
    v-on:focus="onFocus"
    v-on:blur="onBlur"
    @input="onInput"
  />
</template>

<script>
import { ref, computed, defineComponent } from "vue";

export default defineComponent({
  props: {
    modelValue: {
      required: true,
    },
  },
  setup(props, context) {
    const isFocus = ref(false);

    const commaSeparetedValue = computed(() => {
      if (props.modelValue === null) {
        return "";
      }

      return isFocus.value
        ? props.modelValue
        : Number(props.modelValue).toLocaleString();
    });

    const onFocus = () => {
      isFocus.value = true;
    };

    const onBlur = () => {
      isFocus.value = false;
    };

    const onInput = (event) => {
      const value = event.target.value;
      if (isNaN(value)) {
        return;
      }
      context.emit("update:modelValue", value);
    };

    return {
      commaSeparetedValue,
      onFocus,
      onBlur,
      onInput,
    };
  },
});
</script>

<style scoped>
input {
  text-align: right;
}
</style>

呼び出し側

App.vue
<template>
  <p>カンマ区切りのInput</p>
  <CommaInput v-model="inputItem" />
</template>

<script>
import { ref } from "vue";
import CommaInput from "./components/CommaInput.vue";
export default {
  name: "App",
  components: {
    CommaInput,
  },
  setup() {
    const inputItem = ref(null);

    return {
      inputItem,
    };
  },
};
</script>

ソースコード解説 (CommaInput.vue について)

template

<template>
  <input
    :value="commaSeparetedValue"
    v-on:focus="onFocus"
    v-on:blur="onBlur"
    @input="onInput"
  />
</template>

主題のコンポーネントは、focus, blur, inputのイベントを制御する必要があるため、それぞれのイベントの受け取りを設定します。
表示する値については、カンマ区切りの文字列として表示する場合(blur時)と、通常の数値を表示する場合(focus時)があるため、computedな値をバインドする必要があります。
そのため、:value(v-bind:valueの省略記法)を用い、のちに解説するcommaSeparetedValueをバインドします。

script

propsについて

<script>
import { ref, computed, defineComponent } from "vue";

export default defineComponent({
  props: {
    modelValue: {
      required: true,
    },
  },
~省略~
});
</script>

主題のコンポーネントは、使用側がv-modelディレクティブで入力値をセットできる必要があるため、propsにはv-model="hoge"として使用するための予約語であるmodelValueを宣言します。
今回はv-model="hoge"として使用するためにmodelValueとしましたが、v-model:hogeとして使用したい場合は、propsもhogeとします。
後述するemitの特別な記載方法によって、使用側がv-modelディレクティブを使用できるようになります。

setupについて

こちらは解説項目が多いため、ソースコードにコメントで記載しております。

// setup関数の引数に props(表示制御に使用するため), context(emitで使用するため)を受け取る
setup(props, context) {
    // 該当要素がフォーカス状態であるかを保持するリアクティブな値を宣言
    const isFocus = ref(false);
    
    // isFocusに応じて表示する内容を決定する算出プロパティ
    const commaSeparetedValue = computed(() => {
      // null時には空白を表示させる
      // これがないと、入力値がnullの場合に0が表示される
      if (props.modelValue === null) {
        return "";
      }

      // カンマ区切りには標準のtoLocaleString()メソッドを使用
      return isFocus.value
        ? props.modelValue
        : Number(props.modelValue).toLocaleString();
    });

    // focusイベントで使用
    const onFocus = () => {
      isFocus.value = true;
    };

    // blurイベントで使用
    const onBlur = () => {
      isFocus.value = false;
    };

    // inputイベントで使用
    const onInput = (event) => {
      const value = event.target.value;
      // 数値以外の入力を許容しない
      if (isNaN(value)) {
        return;
      }

      // emitの予約語である "update:modelValue(引数名)"を使用 これにより使用側がv-modelディレクティブを使える
      // 例: propsのhogeに対して使用側がv-modelを使用する場合、emitは以下のように記載
      // context.emit("update:hoge", value);
      // 上記の場合、使用側は v-model:hoge="hoge" として使用可能
      context.emit("update:modelValue", value);
    };

    return {
      commaSeparetedValue,
      onFocus,
      onBlur,
      onInput,
    };
  },

まとめ

今回はカンマ区切りのinputコンポーネントの作成について解説しました。
上記のようなコンポーネントは、よくある要望だと思います。
しかし、Vue3系での情報などが少なかったため、記事にしてみました。

また、記載したコードのようにv-modelディレクティブなどを自前で実装できるようになると、プロジェクトを通して共通的に使用するコンポーネントを作成する際のクオリティが上がるかと思います。
ぜひ使ってみてください!!

3
1
2

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
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?