|
|
- <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>
|