有两种输入方式, 一种是只能输入整数, 另一种是能输入特定位数的小数
先定义两个处理函数
/** 转正整数 */
export function toPositiveInteger(str: string) {
const value = str.replace(/((?![0-9]).)*/g, '');
if (!value) return value;
return Number(value).toString();
}
/** 转数字 */
export function toNumber(str: string, fixedCount: number) {
let value = str.replace(/[^\d.]/g, '');
if (!value.includes('.')) return Number(value).toString(); // 没有小数
const valueAry = value.split('.');
value = valueAry[0].concat('.').concat(valueAry[1].slice(0, fixedCount));
if (value.endsWith('.')) return value;
return Number(value).toString();
}
然后写自定义指令
const directive: Directive = {
mounted(el: HTMLElement, binding, vnode) {
const inputEl =
el.tagName.toUpperCase() === 'INPUT'
? (el as HTMLInputElement)
: el.querySelector('input');
if (!inputEl) {
throw new Error('未找到 input 元素');
}
let fixedCount = 0;
if (binding.modifiers.fixed) {
fixedCount = 2; // 默认保留两位小数
if (binding.value) {
if (
!(
typeof binding.value === 'number' ||
typeof binding.value === 'string'
) ||
!/^[0-9]+$/.test(binding.value.toString())
) {
throw new Error('v-number.fixed 绑定的值只能为正整数');
}
}
}
/** 只能输入小数 和 . */
const keyPressEvent = (e: KeyboardEvent) => {
if (!/\d|\./.test(e.key) || (!fixedCount && e.code === '.')) {
return e.preventDefault();
}
};
const keyDownEvent = (e: KeyboardEvent) => {
const value = inputEl.value;
if (!fixedCount) {
inputEl.value = toPositiveInteger(value);
} else {
inputEl.value = toNumber(value, fixedCount);
}
// 这里可以优化下。 判断是不是组件。如果是组件, 触发 emit('input')
// 但是我没有找到 vue3 怎么判断是不是组件
/** 同步一下值 */
inputEl.dispatchEvent(
new CustomEvent('input', {
detail: inputEl.value,
})
);
};
// 监听按下事件。 只能输入数字和小数点
inputEl.addEventListener('keypress', keyPressEvent);
inputEl.addEventListener('keydown', keyDownEvent);
// 组件卸载的时候可以 removeEventListener
},
};