こんにちは!
長らくプレーンJavaScriptガリゴリマンでしたが、最近仕事の関係でVue.jsを触り始めた和尚でございます
それでは早速見ていきましょう!
環境
- Vue.js v2.6.11
- Vuex v3.4.0
- Vuetify v2.2.11
注意
※かなりパワープレイです。参考程度に見てください。
本日の議題
ある昼下がりのこと
Aさん「数値しか入れられないフォームに文字が入っちゃうんだけど、どうにかならない?あと、最大値が999のはずなのに、キーボードで入力すると1000以上入っちゃうからついでに直して...」
和尚「まじっすかー。ちょっと調べてみまーす!」
...
今回の要件における Input type="number" の困った仕様
- 最大値と最小値はキーボード入力で超えることが可能
- safariは文字列を入力すると自動削除されない
- chromeは指数表現のe・Eが入力できる
解決しよう!
それではAさんの要件に沿って修正していきましょう!
修正前のサンプルコンポーネントとストアはこちらになります!
<template>
<div>
<v-text-field
ref="count"
label="カウント"
type="number"
v-model="count"
max="999"
min="1"
/>
</div>
</template>
<script>
export default {
computed: {
count: {
get() {
return this.$store.getters['count'];
},
set(num) {
this.$store.commit('changeCount', num);
}
}
}
}
</script>
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
count: 1
},
getters: {
count: (state) => state.count
},
mutations: {
changeCount(state, num) {
if (num) state.count = num;
}
},
actions: {}
})
①数値のみが入るようにする
テキストフィールドのvalueに文字列が入力された場合は空文字が返却されます。なのでsafariで文字列が入力されたままでもストアで管理している値に文字列が入ることはありません。(空文字を除く)
ということは、テキストフィールドの中にはvalueとは違う値が表示されているということです。
まずはテキストフィールドに数値のみしか入らないように修正していきましょう!
算術プロパティに記述した、countのsetterの中を少し弄ってテキストフィールドに現在のvalueの値が表示されるようにしましょう!
<script>
export default {
computed: {
count: {
get() {
return this.$store.getters['count'];
},
set(num) {
num = parseInt(num)
if (Number.isNaN(num) || num < 1) {
num = 1;
}
this.$refs.count.lazyValue = num;
this.$store.commit('changeCount', num);
}
}
}
}
</script>
- valueをparseIntを使用して文字列から数値にする (Input type="number"の値はString型です)
- 数値ではない場合にnumに1を代入
-
this.$refs.count.lazyValue
に値を入れる (v-text-fieldの表示している値を格納しているプロパティ) - ストアの値も変更する
②最大値・最小値の制御
ここまで来たらあとは簡単!
最大値と最小値の制御を入れてあげましょう!
<script>
export default {
computed: {
count: {
get() {
return this.$store.getters['count'];
},
set(num) {
const min = Number(this.$refs.count.$attrs.min);
const max = Number(this.$refs.count.$attrs.max);
num = parseInt(num)
if (Number.isNaN(num) || num < min) {
num = min;
} else if (num > max) {
num = max;
}
this.$refs.count.lazyValue = num
this.$store.commit('changeCount', num);
}
}
}
}
</script>
-
this.$refs.count
の下に$attrs
という属性値が格納されたプロパティがあるので、そこから最大値と最小値を取り出します。 - 文字もしくは最小値以下だった場合は、最小値を代入
- 最大値を超えた値が入力された場合は最大値を代入
完成!!
これでchromeでもsafariでも問題なく、要件を満たすことができました!
this.$refs.count.lazyValue
を見つけるまでは、ネットで似たようなことをしている記事を探しては試していました。しかし完璧に要件を満たせる方法がなくて諦めかけてたところ、何となくconsole.log(this.$refs.count)を書いてプロパティみてたらそれっぽい値を発見しました!そして、うまく値を書き換えることに成功笑
結構稀な対応かとは思いますが、同様のパターンを実装されたい方は是非参考にしていただけると幸いです。
もっと良い案があればコメントください!
ではでは!