在 Vue3 中处理 number 类型输入框避免显示 NaN,核心在于正确处理用户输入的非数字值。以下是几种解决方案:
方案1:使用字符串中转 + 计算属性(推荐)
vue
复制
下载
<template>
<input
v-model="inputValue"
type="text"
@blur="handleBlur"
placeholder="请输入数字"
>
</template>
<script setup>
import { ref, computed } from 'vue'
const numberValue = ref(0) // 存储实际数字值
const inputValue = computed({
get: () => numberValue.value.toString(),
set: (newValue) => {
// 过滤非数字字符(保留负号和小数点)
const filtered = newValue.replace(/[^0-9.-]/g, '')
// 处理多个负号/小数点
let cleanValue = filtered
.replace(/(?!^)-/g, '') // 保留开头的负号
.replace(/(\..*)\./g, '$1') // 保留第一个小数点
// 更新输入框显示
inputValue.value = cleanValue
// 转换数字并更新存储值
const num = parseFloat(cleanValue)
if (!isNaN(num)) {
numberValue.value = num
}
}
})
// 失焦时清理无效输入
const handleBlur = () => {
if (inputValue.value === '-' || inputValue.value === '.') {
inputValue.value = ''
numberValue.value = 0
}
}
</script>
方案2:使用自定义指令(输入过滤)
vue
复制
下载
<template>
<input
v-model="numberValue"
v-number-input
type="text"
>
</template>
<script setup>
import { ref } from 'vue'
const numberValue = ref(0)
// 自定义指令
const vNumberInput = {
mounted(el) {
el.addEventListener('input', (e) => {
let value = e.target.value
// 移除非数字字符(保留负号和小数点)
value = value.replace(/[^\d.-]/g, '')
// 处理多个负号/小数点
value = value.replace(/(?!^)-/g, '').replace(/(\..*)\./g, '$1')
e.target.value = value
})
}
}
</script>
方案3:使用 watch + 正则过滤(简单场景)
vue
复制
下载
<template>
<input v-model="inputValue" type="text">
</template>
<script setup>
import { ref, watch } from 'vue'
const inputValue = ref('')
const numberValue = ref(0)
watch(inputValue, (newVal) => {
// 清理非法字符
const cleanValue = newVal.replace(/[^\d.-]/g, '')
.replace(/(?!^)-/g, '')
.replace(/(\..*)\./g, '$1')
// 更新显示值
if (newVal !== cleanValue) {
inputValue.value = cleanValue
}
// 转换数字
const num = parseFloat(cleanValue)
numberValue.value = isNaN(num) ? 0 : num
})
</script>
关键处理点:
-
输入过滤:
-
使用正则
/[^\d.-]/g移除非数字字符(保留负号和小数点) -
处理多个负号:
replace(/(?!^)-/g, '') -
处理多个小数点:
replace(/(\..*)\./g, '$1')
-
-
NaN 处理:
-
使用
parseFloat()转换 -
用
isNaN()检测,无效时回退默认值(如 0)
-
-
边界情况:
-
单独负号/小数点时(
"-"或".")在 blur 时清理 -
空字符串处理为 0
-
-
用户体验:
-
允许中间编辑(不强制即时转换)
-
失焦时做最终清理
-
为什么避免直接使用 type="number"?
-
浏览器原生数字输入框:
-
仍可能提交空值/无效值
-
在不同浏览器表现不一致
-
无法完全控制显示内容
-
会显示原生增减按钮(可能不符合UI需求)
-
推荐使用 方案1(字符串中转 + 计算属性),它提供了最完整的控制逻辑,同时保持了 Vue 的响应式特性。



















