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]テキストで数値を入力できるrefを作ろう

Last updated at Posted at 2025-01-31

input[type="number"]を使うよりtextつかってあげるのが優しいようなので,そんなrefを作りたいと思います

↓参考になりました。ありがとうございます!↓

こんなかんじ

2025-01-31 19-20-46.gif

全角を半角に変換しさらに関係ない文字を無視してくれるやさしいrefになっています

実装

composableにするか迷ったのですが、面白い機能があったのでcustomRefを使います

・source

このソースは最初のバージョンで、メンテされていないので最新ソースは追記から確認おねがいします

stringNumberRef.ts
import {customRef} from 'vue'

type StringNumberRefOptions = {
  // マイナス許可?
  allowMinus: boolean,
  // 小数点許可?
  allowDecimal: boolean
}

// 全角数値を半角数値にreplaceするやさしいrefです
export function stringNumberRef(
  value: string,
  options: StringNumberRefOptions = {allowDecimal: false, allowMinus: false}
) {
  let internalValue = getValue(value, options);

  return customRef((track, trigger) => {
    return {
      get() {
        track()
        return internalValue
      },
      set(v) {
        internalValue = getValue(v, options)
        trigger()
      }
    }
  })
}

// 変換後の値を返す
function getValue(v: string, options: StringNumberRefOptions) {
  if (v.trim() === "") {
    return ""
  }
  if (isFinite(Number(v))) {
    return v
  }
  const replaced = toHalfWidth(v)
  if (replaced === "-") {
    return replaced
  }
  const allowed = replaced.match(/-?\d+(?:\.\d+)?/)
  if (allowed === null) {
    return ""
  }
  return getNumberText(allowed[0], options)
}

function toHalfWidth(str: string) {
  return str.replace(/[0-9.ー]/g, (c) =>
    c === "" ? "-" : String.fromCharCode(c.charCodeAt(0) - 0xFEE0)
  );
}

function getNumberText(stringNumber: string, options: StringNumberRefOptions) {
  let number = parseFloat(stringNumber)
  if (!options.allowMinus) {
    number = Math.abs(number)
  }
  if (!options.allowDecimal) {
    number = Math.trunc(number)
  }
  return `${number}`;
}

・使い方

<script setup lang="ts">
import {stringNumberRef} from "../stringNumberRef.ts";

const text = stringNumberRef("")
const dec = stringNumberRef("", {allowDecimal: true, allowMinus: false})
const min = stringNumberRef("", {allowDecimal: false, allowMinus: true})
const all = stringNumberRef("", {allowDecimal: true, allowMinus: true})
</script>

<template>
  <div>
    <p>整数のみ <input type="text" v-model="text" inputMode="numeric"></p>
    <p>小数点許可 <input type="text" v-model="dec" inputMode="numeric"></p>
    <p>マイナス許可 <input type="text" v-model="min" inputMode="numeric"></p>
    <p>小数点+マイナス許可 <input type="text" v-model="all" inputMode="numeric"></p>
  </div>
</template>

おわり

以外に複雑だったのでgithubにあげてテスト書きたいな

bugはあるかもしれません :sweat:

追記

githubにソースを上げて、テストも書きました
バグ修正などはそちらに入れていきたいと思います

さらにnpmにも上げてみたので以下コマンドで簡単にインストールしてお試しできます :thumbsup:

npm i vue-string-number-ref
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?