feat(common): ✨ 添加input-rules
This commit is contained in:
@@ -3,3 +3,4 @@ export * from "./permission";
|
||||
export * from "./printer";
|
||||
export * from "./time";
|
||||
export * from "./timer";
|
||||
export * from "./input-rule";
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* @file: /src/input-rule.ts
|
||||
* @description: 限制输入框输入的规则
|
||||
* @author: tsl (randy1924@163.com)
|
||||
* @date: 2026-03-18 13:37:11
|
||||
* @lastModified: 2026-03-18 15:04:44
|
||||
* @lastModifiedBy: tsl (randy1924@163.com)
|
||||
*/
|
||||
|
||||
export type InputValue = string | number | null;
|
||||
export interface InputOptions {
|
||||
min?: number; // 最小值
|
||||
max?: number; // 最大值
|
||||
init?: string | number; // 初始值
|
||||
digits?: number; // 小数位数
|
||||
pattern?: string | RegExp; // 匹配模式
|
||||
required?: boolean; // 是否必填
|
||||
integer?: boolean; // 是否整数
|
||||
number?: boolean; // 是否转成数字
|
||||
text?: boolean; // 是否使用文本模式
|
||||
floor?: boolean; // 是否向下取数
|
||||
ceil?: boolean; // 是否向上取数
|
||||
keepDecimal?: boolean; // 是否保留小数,即使是小数位是0
|
||||
noSign?: boolean; // 不允许输入正负号
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据规则获取目标值
|
||||
* @example
|
||||
* 限制输入的最小值:0,最大值:99999.99,必填,小数位数:2
|
||||
* const value = getValueOfRule(e.detail.value, {
|
||||
* min: 0,
|
||||
* max: 99999.99,
|
||||
* required: true,
|
||||
* digits: 2,
|
||||
* })
|
||||
*/
|
||||
export function getValueOfRule(
|
||||
value: InputValue,
|
||||
options: InputOptions,
|
||||
callback?: (value: InputValue) => void,
|
||||
): InputValue {
|
||||
console.log("getValueOfRule", value, options);
|
||||
|
||||
const { text } = options;
|
||||
|
||||
let targetValue: InputValue;
|
||||
if (text) {
|
||||
targetValue = getTextTargetValue(value, options);
|
||||
} else {
|
||||
targetValue = getNumberTargetValue(value, options);
|
||||
}
|
||||
|
||||
console.log("targetValue", targetValue);
|
||||
callback?.(targetValue);
|
||||
return targetValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据输入的获取处理后值-文本类型
|
||||
*/
|
||||
function getTextTargetValue(innerValue: InputValue, options: InputOptions): InputValue {
|
||||
const { required, init, pattern, number } = options;
|
||||
|
||||
innerValue ??= "";
|
||||
|
||||
innerValue = String(innerValue);
|
||||
let targetValue: string | number = innerValue;
|
||||
|
||||
// 如果提供了pattern参数,检查输入是否匹配该模式
|
||||
if (pattern && !new RegExp(pattern).test(innerValue)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!/^[+-]?\d+(\.\d+)?$/.test(innerValue)) {
|
||||
if (required) {
|
||||
if (init !== undefined) {
|
||||
targetValue = String(init);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (number) {
|
||||
targetValue = Number(targetValue);
|
||||
}
|
||||
|
||||
return targetValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 floor/ceil 选项选择取整方式
|
||||
*/
|
||||
function getRoundFn(floor?: boolean, ceil?: boolean): (n: number) => number {
|
||||
if (floor) return Math.floor;
|
||||
if (ceil) return Math.ceil;
|
||||
return Math.round;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断字符串是否为合法数字输入
|
||||
*/
|
||||
function isValidNumberInput(value: string, noSign?: boolean): boolean {
|
||||
if (!value) return false;
|
||||
if (!/^[+-]?\d+(\.\d+)?$/.test(value)) return false;
|
||||
if (noSign && /[+-]/.test(value)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取非法输入时的回退值
|
||||
*/
|
||||
function getFallbackValue(options: InputOptions): string {
|
||||
const { required, init, min } = options;
|
||||
if (!required) return "";
|
||||
if (init != null) return String(init);
|
||||
return min == null ? "0" : String(min);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对数字应用精度和取整处理
|
||||
*/
|
||||
function applyPrecision(num: number, options: InputOptions): number {
|
||||
const { digits, integer, floor, ceil, min, max } = options;
|
||||
let result = num;
|
||||
|
||||
if (min != null) result = Math.max(result, min);
|
||||
if (max != null) result = Math.min(result, max);
|
||||
|
||||
const roundFn = getRoundFn(floor, ceil);
|
||||
|
||||
if (digits != null) {
|
||||
const precision = Math.pow(10, digits);
|
||||
result = roundFn(result * precision) / precision;
|
||||
}
|
||||
|
||||
if (integer) {
|
||||
result = roundFn(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据输入的获取处理后值-数字类型
|
||||
*/
|
||||
function getNumberTargetValue(innerValue: InputValue, options: InputOptions): InputValue {
|
||||
const { number, keepDecimal, noSign, digits } = options;
|
||||
const strValue = String(innerValue ?? "");
|
||||
|
||||
let targetValue: string;
|
||||
|
||||
if (isValidNumberInput(strValue, noSign)) {
|
||||
targetValue = String(applyPrecision(Number(strValue), options));
|
||||
} else {
|
||||
targetValue = getFallbackValue(options);
|
||||
}
|
||||
|
||||
if (digits != null && keepDecimal) {
|
||||
targetValue = Number(targetValue).toFixed(digits);
|
||||
}
|
||||
|
||||
return number ? Number(targetValue) : targetValue;
|
||||
}
|
||||
Reference in New Issue
Block a user