华西海圻ELN前端工程
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

148 lines
4.3 KiB

<template>
<el-input v-bind="$attrs" v-model="internalValue" @input="handleInput" @blur="handleBlur" :placeholder="placeholder"
:disabled="disabled" type="text">
<template slot="prepend" v-if="prepend">
{{ prepend }}
</template>
</el-input>
</template>
<script>
export default {
name: 'DecimalInput',
props: {
value: {
type: [Number, String],
default: ''
},
decimalDigits: {
type: Number,
default: 3
},
placeholder: {
type: String,
default: '请输入'
},
disabled: {
type: Boolean,
default: false
},
prepend: {
type: String,
default: ''
},
},
data() {
return {
internalValue: this.value !== null && this.value !== undefined ? String(this.value) : ''
};
},
watch: {
value(newVal) {
// 外部值变化时同步到内部(但不做格式化,避免干扰用户输入)
console.log(newVal,"newVal")
if (newVal === '' || newVal == null) {
this.internalValue = '';
} else {
this.internalValue = String(newVal);
}
}
},
methods: {
handleInput(val) {
console.log(val,"val")
if (val === '') {
this.internalValue = '';
this.$emit('input', '');
return;
}
// 1. 只保留数字、小数点、开头的负号
let cleaned = val
.replace(/[^\d.-]/g, '')
.replace(/^(-)\1+/, '$1'); // 合并多个负号
// 2. 只保留第一个小数点
const firstDotIndex = cleaned.indexOf('.');
if (firstDotIndex !== -1) {
const before = cleaned.slice(0, firstDotIndex);
const after = cleaned.slice(firstDotIndex + 1).replace(/\./g, '');
cleaned = before + '.' + after;
}
// 3. 限制小数位数(仅当允许小数时)
if (this.decimalDigits > 0 && cleaned.includes('.')) {
const [intPart, decPart = ''] = cleaned.split('.');
cleaned = intPart + '.' + decPart.slice(0, this.decimalDigits);
} else if (this.decimalDigits === 0) {
cleaned = cleaned.split('.')[0]; // 移除小数部分
}
// 4. 处理以 . 或 -. 开头
if (cleaned === '.') cleaned = '0.';
else if (cleaned === '-.') cleaned = '-0.';
else if (cleaned.startsWith('.')) cleaned = '0' + cleaned;
else if (cleaned.startsWith('-.')) cleaned = '-0.' + cleaned.slice(2);
// 5. 【关键】安全去除前导零,但保留单个 0
if (cleaned.includes('.')) {
// 有小数点:处理整数部分
const [int, dec] = cleaned.split('.');
// 整数部分:-0012 → -12,00 → 0,0 → 0,-0 → 0(或保留 -0)
let newInt = int;
if (/^-?0+\d/.test(int)) {
newInt = int.replace(/^-?0+(\d)/, '$1');
} else if (int === '' || int === '-') {
newInt = int + '0';
} else if (int === '00' || /^-00+$/.test(int)) {
newInt = int.startsWith('-') ? '-0' : '0';
}
cleaned = newInt + '.' + dec;
} else {
// 无小数点
if (/^-?0+\d/.test(cleaned)) {
cleaned = cleaned.replace(/^-?0+(\d)/, '$1');
} else if (cleaned === '00' || /^-00+$/.test(cleaned)) {
cleaned = cleaned.startsWith('-') ? '-0' : '0';
}
// 注意:不要把单独的 '0' 变成 ''
}
this.internalValue = cleaned;
// emit
if (cleaned === '' || cleaned === '-') {
this.$emit('input', cleaned === '-' ? '-' : '');
} else {
const num = parseFloat(cleaned);
console.log(num,isNaN(num),"num")
this.$emit('input', isNaN(num) ? '' : num);
}
},
handleBlur() {
let finalValue = this.internalValue.trim();
if (finalValue === '' || finalValue === '-') {
this.internalValue = '';
this.$emit('input', '');
return;
}
const num = parseFloat(finalValue);
if (isNaN(num)) {
this.internalValue = '';
this.$emit('input', '');
return;
}
// 在 blur 时才做 toFixed(四舍五入 + 补零)
const formatted = num.toFixed(this.decimalDigits);
this.internalValue = formatted;
// emit 数字类型(也可 emit 字符串,根据需求)
this.$emit('input', parseFloat(formatted));
this.$emit('blur', parseFloat(formatted));
}
}
};
</script>