在 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-inputtype="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 的響應式特性。