步骤 1:创建自定义指令
function processValue(value) {
let filtered = value.replace(/[^\d.]/g, '');
const firstDotIndex = filtered.indexOf('.');
if (firstDotIndex !== -1) {
filtered = filtered.substring(0, firstDotIndex + 1) + filtered.substring(firstDotIndex + 1).replace(/\./g, '');
}
const parts = filtered.split('.');
let integerPart = (parts[0] || '').slice(0, 10);
let decimalPart = parts.length > 1 ? parts[1].slice(0, 2) : '';
if (filtered.startsWith('.') && integerPart === '') {
integerPart = '0';
}
let newValue = integerPart;
if (parts.length > 1 || filtered.endsWith('.')) {
newValue += '.' + decimalPart;
}
return newValue;
}
Vue.directive('number', {
bind(el, binding, vnode) {
const input = el.querySelector('input.el-input__inner');
if (!input) return;
let composing = false;
const handler = (e) => {
if (composing) return;
const newVal = processValue(e.target.value);
if (e.target.value !== newVal) {
e.target.value = newVal;
input.dispatchEvent(new Event('input', { bubbles: true }));
}
};
const compositionStart = () => { composing = true; };
const compositionEnd = (e) => {
composing = false;
handler(e);
};
input.addEventListener('compositionstart', compositionStart);
input.addEventListener('compositionend', compositionEnd);
input.addEventListener('input', handler);
el._numberHandlers = { compositionStart, compositionEnd, handler };
const initialValue = vnode.componentInstance?.value ?? input.value;
const processedVal = processValue(initialValue);
if (initialValue !== processedVal) {
vnode.componentInstance?.$emit('input', processedVal);
}
},
update(el, binding, vnode) {
const input = el.querySelector('input.el-input__inner');
const currentValue = vnode.componentInstance?.value ?? input?.value;
if (currentValue === undefined) return;
const newVal = processValue(currentValue);
if (currentValue !== newVal) {
vnode.componentInstance?.$emit('input', newVal);
}
},
unbind(el) {
const input = el.querySelector('input.el-input__inner');
if (input && el._numberHandlers) {
const { compositionStart, compositionEnd, handler } = el._numberHandlers;
input.removeEventListener('compositionstart', compositionStart);
input.removeEventListener('compositionend', compositionEnd);
input.removeEventListener('input', handler);
delete el._numberHandlers;
}
}
});
步骤 2:在组件中使用指令
<template>
<el-input v-number v-model="inputValue"></el-input>
</template>
<script>
export default {
data() {
return {
inputValue: ''
};
}
};
</script>
功能说明
- 过滤非数字字符:只允许输入数字和小数点。
- 限制小数点数量:确保只保留第一个小数点,后续的自动移除。
- 整数部分限制:最多输入 10 位整数,超长部分截断。
- 小数部分限制:最多输入 2 位小数,超长部分截断。
- 输入法兼容:处理中文输入法状态,避免中途过滤。
- 初始值处理:当初始值不符合规则时自动修正。
- 实时更新:通过触发
input
事件确保 v-model
同步更新。
注意事项
- 该指令依赖于 Element UI 的
el-input
结构,确保内部输入框的类名为 el-input__inner
。 - 处理后的值会覆盖用户输入,确保始终符合规则。
- 支持输入法组合输入(如中文拼音),提升用户体验。