input[type="number"]を使うよりtextつかってあげるのが優しいようなので,そんなrefを作りたいと思います
↓参考になりました。ありがとうございます!↓
こんなかんじ
全角を半角に変換しさらに関係ない文字を無視してくれるやさしい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はあるかもしれません
追記
githubにソースを上げて、テストも書きました
バグ修正などはそちらに入れていきたいと思います
さらにnpmにも上げてみたので以下コマンドで簡単にインストールしてお試しできます
npm i vue-string-number-ref