isNumberKey与truncateDecimals组合导致输入框异常舍入问题
Hey Paul, I see the frustrating issue you're stuck on—this is a classic floating-point precision quirk that trips up a lot of developers! Let's break down what's happening and fix it for good.
The Root Cause
Your truncateDecimals function uses Math.floor(obj.value * divisor) / divisor, but here's the problem: decimal values like 10.2 can't be represented perfectly in binary floating-point format. When you calculate 10.2 * 100, instead of getting exactly 1020, you actually end up with something like 1019.9999999999998. Math.floor() then chops that down to 1019, and dividing by 100 gives you 10.19 instead of the expected 10.2.
The Fixes
We can work around this floating-point limitation with two reliable approaches:
Solution 1: Fix the Calculation with Pre-Rounding
Before applying Math.floor(), round the multiplied value to the nearest integer to eliminate the tiny precision error:
function truncateDecimals(obj, decimals) { if (!obj.value || isNaN(parseFloat(obj.value))) { return true; } const num = parseFloat(obj.value); const divisor = Math.pow(10, decimals); // Round first to fix floating-point imprecision, then apply floor obj.value = Math.floor(Math.round(num * divisor)) / divisor; console.log(obj.value); return true; }
Solution 2: String-Based Truncation (More Intuitive)
If you want to avoid floating-point math entirely, split the number by the decimal point and truncate the string directly:
function truncateDecimals(obj, decimals) { if (!obj.value) return true; const [integerPart, decimalPart = ''] = obj.value.split('.'); // Truncate the decimal part to the desired length const truncatedDecimal = decimalPart.slice(0, decimals); // Reconstruct the number (handle cases where there's no decimal part) obj.value = truncatedDecimal ? `${integerPart}.${truncatedDecimal}` : integerPart; console.log(obj.value); return true; }
Bonus: Improve the isNumberKey Function
Your current isNumberKey might block useful keys like backspace, delete, or arrow keys. Here's a tweaked version that allows those while still restricting input to valid numbers:
function isNumberKey(evt) { const charCode = evt.which || evt.keyCode; // Allow control keys like backspace, delete, arrows, and tab const allowedControlKeys = [8, 9, 46, 37, 38, 39, 40]; if (allowedControlKeys.includes(charCode)) { return true; } // Allow numbers (48-57) and single decimal point (46) if (charCode > 31 && (charCode < 48 || charCode > 57) && charCode !== 46) { evt.preventDefault(); return false; } // Prevent multiple decimal points in the input if (charCode === 46 && evt.target.value.includes('.')) { evt.preventDefault(); return false; } return true; }
Either of the truncate fixes should resolve your 10.2 → 10.19 issue. Give them a test run!
内容的提问来源于stack exchange,提问作者Paul Davis

