如何用Vuetify创建支持整数限制的数字输入组件?
Vuetify数字输入组件开发问题
需求
- 输入输出值支持
undefined或null(清空字段时不返回0) - 组件尽量隐藏增减按钮
- 当
isAcceptingFloatingPointNumbers = false时,仅允许输入整数,禁止浮点数输入
初始实现代码
<template> <v-app> <v-main> <v-text-field type="number" label="number input" :clearable="true" :model-value="num" @update:modelValue="num = $event" /> </v-main> </v-app> </template> <script setup lang="ts"> import { ref, watch, Ref } from 'vue' const num: Ref<unknown> = ref(undefined) watch(num, () => console.log(num.value)) </script>
现有问题
曾尝试添加自定义校验规则:
v => Number.isInteger(v) || 'Must be integer'
但该规则会在值为undefined时触发提示,因此希望直接阻止非法输入而非事后校验。
基于参考实现了按键过滤逻辑,但当前过滤函数存在漏洞:当isAcceptingFloatingPointNumbers = false时,仍能输入12.4——因为拼接字符串转数字时会忽略小数点,将12.4识别为124,导致无法正确拦截小数点输入。
当前组件代码
NumberField.vue
<template> <v-text-field type="number" label="number input" :clearable="true" :model-value="num" @update:modelValue="emit('update:modelValue', $event)" @keypress="filterInput" /> </template> <script setup lang="ts"> const props = defineProps<{ num: unknown; isAcceptingFloatingPointNumbers: boolean; }>(); const emit = defineEmits<{ (e: "update:modelValue", newValue: unknown): void; }>(); function filterInput(inputEvent) { if(props.isAcceptingFloatingPointNumbers.value) { return true; } const inputAsString = inputEvent.target.value.toString() + inputEvent.key.toString(); const inputValue = Number(inputAsString); if(!Number.isInteger(inputValue)) { inputEvent.preventDefault(); } return true; } </script>
消费组件代码
<template> <number-field :num="num" :isAcceptingFloatingPointNumbers="false" @update:model-value="num = $event" /> </template> <script setup lang="ts"> import { ref, watch } from 'vue' import NumberField from "./NumberField.vue"; const num: Ref<unknown> = ref(undefined); watch(num, () => console.log(num.value)); </script>
修复方案
问题核心在于原过滤逻辑通过拼接字符串转数字的方式判断合法性,会自动忽略小数点导致误判。正确做法是直接校验输入按键的合法性,同时处理控制键(退格、方向键等)的允许逻辑,再配合样式隐藏增减按钮、值同步处理确保清空时返回undefined。
最终完整NumberField.vue代码
<template> <v-text-field type="number" label="number input" :clearable="true" :model-value="num" @update:modelValue="handleUpdate" @keypress="filterInput" class="no-spin-buttons" /> </template> <script setup lang="ts"> import type { KeyboardEvent } from 'vue'; const props = defineProps<{ num: number | undefined | null; isAcceptingFloatingPointNumbers: boolean; }>(); const emit = defineEmits<{ (e: "update:modelValue", newValue: number | undefined | null): void; }>(); // 处理值更新,清空时返回undefined function handleUpdate(value: unknown) { const newValue = value === '' ? undefined : value; emit('update:modelValue', newValue as number | undefined | null); } // 按键过滤逻辑 function filterInput(inputEvent: KeyboardEvent) { const { key } = inputEvent; // 允许控制键(退格、删除、方向键等) if (inputEvent.ctrlKey || inputEvent.metaKey || inputEvent.key.length !== 1) { return true; } if (!props.isAcceptingFloatingPointNumbers) { // 整数模式:仅允许数字键(0-9) if (!/^\d$/.test(key)) { inputEvent.preventDefault(); return false; } } else { // 浮点数模式:允许数字和单个小数点 if (!/^\d$/.test(key) && key !== '.') { inputEvent.preventDefault(); return false; } const currentValue = (inputEvent.target as HTMLInputElement).value; // 已有小数点时禁止再输入 if (key === '.' && currentValue.includes('.')) { inputEvent.preventDefault(); return false; } } return true; } </script> <style scoped> /* 隐藏数字输入框的增减按钮 */ .no-spin-buttons input[type="number"]::-webkit-outer-spin-button, .no-spin-buttons input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } .no-spin-buttons input[type="number"] { -moz-appearance: textfield; } </style>
修复效果说明
- 整数模式下直接拦截非数字按键,彻底禁止小数点输入
- 通过CSS隐藏了数字输入框的增减按钮
- 清空字段时自动返回
undefined,符合需求 - 浮点数模式下限制仅能输入一个小数点,避免非法格式
内容的提问来源于stack exchange,提问作者baitendbidz
相关产品推荐
相关产品推荐

