はじめに
金額系のテキストフィールドを実装する際に以下のようなUI仕様にしたいってありますよね。
- 通常は「100,000」のように3桁でカンマ区切りで数値をテキストフィールドに表示したい
- マウスやTABキーなどでテキストフィールドにカーソルが当たったら「100000」と普通の数値の編集ができる
- カーソルがテキストフィールドから外れたら再び「100,000」の表示になる
今回はVue(Nuxt)でこの機能を実装したテキストフィールドコンポーネントのサンプルコードを紹介します。
これはプロトタイプです。
最低限の機能のみなので、要件に応じてここからpropsなどを追加してアレンジしてくださいね!
デモ
<template>
<div>
<TextField v-model="input" />
<p>親側で取得している値: {{ input }}</p>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import TextField from "@/components/TextField.vue";
const input = ref<string>("100000000");
</script>
テキストフィールドの下にはコンポーネントからv-modelで取得した値を表示しています。
デモでは初期値を入れています。
テキストフィールドコンポーネント
template 部分
今回はかなりシンプルなパターンを想定しています。必要に応じて拡張してください。
<template>
<input
class="TextField"
type="text"
:value="inputValue"
@input="handleInput"
@blur="handleBlur"
@focus="handleFocus"
/>
</template>
使うメソッドのざっくりとした役割は以下です。
イベント | メソッド | 説明 |
---|---|---|
input | handleInput | 入力された文字を取得する |
focus | handleFocus | カンマ付き数値を通常の数値にする |
blur | handleBlur | 数値をカンマ区切りにする |
script 部分
基本仕様の定義
import { ref, onMounted } from "vue";
interface Props {
modelValue?: string;
}
const props = withDefaults(defineProps<Props>(), {
modelValue: "",
});
const emit = defineEmits(["update:modelValue"]);
// 入力値
const inputValue = ref(props.modelValue);
propsは一旦親側でv-modelで取得するためにmodelValueを定義します。
言い換えると、テキストフィールドに入力したテキストはmodelValueに入ります。
inputValue
は、コンポーネント側でmodelValueのテキストにカンマをつけたりとったりした値を入れる上書き用の、いわばmodelValueのコピーのようなイメージです。
propsのmodelValueを直接コンポーネント側で書き換えることは避けるべきなので、上書き用のinputValue
を用意します。
メソッド
// 入力値(数値)をカンマ区切りに変換
const addComma = () => {
if (props.modelValue.length) {
const numModelValue = Number(props.modelValue);
inputValue.value = isNaN(numModelValue)
? props.modelValue
: numModelValue.toLocaleString();
}
};
// フォーカス外
const handleBlur = () => {
addComma();
};
// フォーカス
const handleFocus = () => {
inputValue.value = props.modelValue;
};
// 入力値
const handleInput = (event: Event) => {
inputValue.value = event.target.value;
emit("update:modelValue", inputValue.value);
};
onMounted(() => {
addComma(); // 初期表示時にカンマ区切りに変換
});
書くメソッドの役割は以下です。
メソッド | 説明 |
---|---|
addComma | modelValueに値が入っている、かつ数値だった場合にカンマを付与する |
handleBlur | フォーカスが外れた時にカンマをつける |
handleFocus | フォーカスが当たった時にmodelValueの値を表示する |
handleInput | 入力値をイベントで伝播する |
onMounted | 初期レンダリング後に数値が既に入っていた場合のカンマ表示 |
ポイント
デモを操作していただくと分かると思いますが、テキストフィールドのvalueはカンマをつけたりとったりしていますが、v-modelで親側から取得した値はフォーカスの有無で変化はありません。
「カンマの表示・非表示」というのはあくまで視覚的な要件のお話なので、データを扱う場合にはカンマは不要なケースが多いため、v-modelで取得した値には影響しない仕様にしています。
おわりに
金額系を扱う時に割とあるあるな要件なので、形はすぐ作れるようにしておきたいですね