React Number Format 高级自定义指南:打造专属数字输入组件
核心概念解析
React Number Format 的核心设计理念是提供高度可定制的数字格式化能力,同时确保输入过程中的光标位置管理准确无误。该库通过三个核心函数实现这一目标:
- format函数:将纯数字字符串转换为格式化后的字符串
- removeFormatting函数:从格式化字符串中提取出纯数字字符串
- getCaretBoundary函数:确定哪些光标位置是合法的
基础自定义实现
简单数字格式化示例
import { NumberFormatBase } from 'react-number-format';
function SimpleNumberFormat(props) {
const format = (numStr) => {
if (!numStr) return '';
return new Intl.NumberFormat('en-US').format(numStr);
};
return <NumberFormatBase {...props} format={format} />;
}
这个简单示例展示了如何创建一个基本的数字格式化组件,它会自动为输入的数字添加千位分隔符。
实用场景案例
信用卡有效期输入组件
function CardExpiryFormat(props) {
const format = (val) => {
let month = val.substring(0, 2);
const year = val.substring(2, 4);
// 处理月份边界情况
if (month.length === 1 && month > '1') {
month = `0${month}`;
} else if (month === '00') {
month = '01';
} else if (month > '12') {
month = '12';
}
return month + (year ? `/${year}` : '');
};
return <NumberFormatBase {...props} format={format} />;
}
这个组件会自动处理月份的有效范围(01-12),并在用户输入时自动添加斜杠分隔符。
高级组合技巧
结合现有格式化功能
React Number Format 提供了usePatternFormat
和useNumericFormat
钩子,可以基于现有功能进行扩展:
function EnhancedCardExpiry(props) {
const { format, ...rest } = usePatternFormat({
...props,
format: '##/##'
});
const customFormat = (val) => {
// 自定义格式化逻辑
return format(processedVal);
};
return <NumberFormatBase format={customFormat} {...rest} />;
}
国际化支持
自定义数字显示(如波斯数字)
const persianDigits = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹'];
function PersianNumberFormat(props) {
const { format, removeFormatting, ...rest } = useNumericFormat(props);
const customFormat = (val) => {
return format(val).replace(/\d/g, d => persianDigits[d]);
};
const customRemoveFormatting = (val) => {
const numStr = val.replace(new RegExp(persianDigits.join('|'), 'g'),
m => persianDigits.indexOf(m));
return removeFormatting(numStr);
};
return (
<NumberFormatBase
format={customFormat}
removeFormatting={customRemoveFormatting}
{...rest}
/>
);
}
特殊格式处理
负数的括号表示法
金融应用中常用括号表示负数,如(123)表示-123:
function FinancialNumberFormat(props) {
const [isNegative, setIsNegative] = useState(false);
const format = (numStr) => {
const formatted = defaultFormat(numStr);
return isNegative ? `(${formatted})` : formatted;
};
const handleKeyDown = (e) => {
if (e.key === '-') {
setIsNegative(!isNegative);
e.preventDefault();
}
};
return (
<NumberFormatBase
format={format}
onKeyDown={handleKeyDown}
{...props}
/>
);
}
专业场景实现
IBAN银行账号输入组件
function IBANInput(props) {
return (
<NumberFormatBase
{...props}
format={value =>
value.replace(/\s+/g, '')
.replace(/(.{4})/g, '$1 ')
.trim()
.toUpperCase()
}
removeFormatting={value => value.replace(/\s+/g, '')}
isValidInputCharacter={char => /^[a-z0-9]$/i.test(char)}
/>
);
}
这个组件会自动将输入的IBAN账号格式化为每4个字符一组的格式,并转换为大写字母。
最佳实践建议
- 光标处理:复杂的格式化场景需要特别注意光标位置,可以通过
getCaretBoundary
精细控制 - 性能优化:格式化函数应保持轻量,避免复杂计算
- 输入验证:结合
isValidInputCharacter
确保只允许有效字符输入 - 无障碍访问:确保格式化不影响屏幕阅读器等辅助技术的使用体验
通过掌握这些高级自定义技巧,你可以为任何业务场景创建完美的数字输入解决方案。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考