el-Input输入数字自动转千分位进行展示

el-Input输入数字自动转千分位进行展示,存储值不变

子组件:

javascript 复制代码
<template>
	<el-input ref="inputRef" :disabled="disabled" clearable v-model="displayValue" v-bind="$attrs" @input="handleInput" @focus="handleFocus" @blur="handleBlur" @change="handleChange" @keydown="handleKeyDown" @compositionstart="handleCompositionStart" @compositionend="handleCompositionEnd"></el-input>
</template>

<script>
export default {
	name: 'AmountInput',
	props: {
		value: {
			type: [Number, String],
			default: null,
		},
		disabled: {
			type: Boolean,
			default: false,
		},
		// 新增精度控制属性
		precision: {
			type: Number,
			default: 2,
		},
		// 新增:是否启用大数模式(字符串处理)
		bigNumber: {
			type: Boolean,
			default: true,
		},
	},
	data() {
		return {
			displayValue: '',
			internalValue: null,
			isFocused: false,
			lastValidValue: null,
			isComposing: false, // 标记是否在中文输入法组合输入中
		};
	},
	watch: {
		value: {
			immediate: true,
			handler(newVal) {
				const parsed = this.parseInputValue(newVal);
				if (parsed !== this.internalValue) {
					this.internalValue = parsed;
					this.formatDisplayValue();
				}
			},
		},
	},
	mounted() {
		this.internalValue = this.parseInputValue(this.value);
		this.formatDisplayValue();
	},
	methods: {
		// 确保转换为字符串处理
		safeToString(value) {
			if (value === null || value === undefined) return '';
			return String(value);
		},
		// 处理中文输入法开始
		handleCompositionStart() {
			this.isComposing = true;
		},

		// 处理中文输入法结束
		handleCompositionEnd(e) {
			this.isComposing = false;
			this.handleInput(e.target.value);
		},
		// 处理大数字符串
		processBigNumber(numStr) {
			console.log(numStr, 'numStr');
			if (!numStr) return '';

			// 移除所有非数字字符(保留负号和小数点)
			let cleaned = numStr.replace(/[^\d.-]/g, '');

			// 分离符号、整数和小数部分
			const isNegative = cleaned.startsWith('-');
			if (isNegative) cleaned = cleaned.substring(1);

			const parts = cleaned.split('.');
			let integerPart = parts[0].replace(/^0+/, '') || '0';
			let decimalPart = parts.length > 1 ? parts[1] : '';

			// 截断小数部分
			if (decimalPart.length > this.precision) {
				decimalPart = decimalPart.substring(0, this.precision);
			}

			// 添加千分位
			integerPart = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',');

			// 重新组合
			return (isNegative ? '-' : '') + integerPart + (decimalPart ? `.${decimalPart}` : '');
		},

		formatDisplayValue() {
			if (this.isFocused) {
				this.displayValue = this.internalValue !== null ? this.safeToString(this.internalValue) : '';
			} else {
				this.displayValue = this.formatNumber(this.internalValue);
			}
		},

		parseInputValue(value) {
			if (value === '' || value === null || value === undefined) return null;

			const numStr = this.safeToString(value)
				.replace(/,/g, '')
				.replace(/[^\d.-]/g, '');

			if (numStr === '-' || numStr === '.') return null;

			// 处理大数字符串
			if (numStr.length > 15) {
				return numStr; // 作为字符串返回,避免精度丢失
			}

			const num = Number(numStr);
			return isNaN(num) ? null : num;
		},
		// 修复科学计数法转换
		convertFromScientificNotation(num) {
			if (num === null || num === undefined) return null;

			// 如果是字符串形式的科学计数法
			if (typeof num === 'string' && num.includes('e')) {
				try {
					return Number(num).toString();
				} catch {
					return num;
				}
			}

			// 如果是数值型的科学计数法
			if (typeof num === 'number' && num.toString().includes('e')) {
				return num.toLocaleString('fullwide', { useGrouping: false });
			}

			return num.toString();
		},

		// 增强的数字格式化方法
		formatNumber(value) {
			if (value === null || value === undefined) return '';

			const numStr = this.safeToString(value);
			const isNegative = numStr.startsWith('-');
			const cleanStr = isNegative ? numStr.substring(1) : numStr;

			const parts = cleanStr.split('.');
			let integerPart = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
			let decimalPart = parts.length > 1 ? parts[1].substring(0, this.precision) : '';

			return (isNegative ? '-' : '') + integerPart + (decimalPart ? `.${decimalPart}` : '');
		},

		validateInput(value) {
			if (value === '' || value === null) return true;
			return new RegExp(`^-?\\d*\\.?\\d{0,${this.precision}}$`).test(value);
		},

		handleInput(value) {
			if (this.isComposing) return; // 中文输入法组合期间不处理

			const strValue = this.safeToString(value);
			const filtered = strValue.replace(/[^\d.-]/g, '');

			// 处理多个小数点
			const decimalParts = filtered.split('.');
			let cleanedValue = decimalParts[0];
			if (decimalParts.length > 1) {
				cleanedValue += '.' + decimalParts.slice(1).join('').substring(0, this.precision);
			}

			// 处理负号
			if (cleanedValue.includes('-')) {
				cleanedValue = '-' + cleanedValue.replace(/-/g, '');
			}

			if (cleanedValue !== this.displayValue) {
				this.displayValue = cleanedValue;
			}

			const parsed = this.parseInputValue(cleanedValue);
			this.internalValue = parsed;
			this.lastValidValue = cleanedValue;
			this.$emit('input', parsed);
		},

		handleFocus() {
			this.isFocused = true;
			this.formatDisplayValue();
			this.$emit('focus');
		},

		handleBlur() {
			this.isFocused = false;
			const parsed = this.parseInputValue(this.displayValue);
			this.internalValue = parsed;
			this.formatDisplayValue();
			this.$emit('blur');
			this.$emit('change', parsed);
		},
		handleKeyDown(e) {
			const allowedKeys = [
				8,
				9,
				37,
				39,
				46,
				35,
				36, // 特殊键
				...(e.ctrlKey ? [65, 67, 86, 88] : []), // Ctrl组合键
			];

			if (/\d/.test(e.key) || allowedKeys.includes(e.keyCode) || (e.key === '.' && !this.displayValue.includes('.')) || (e.key === '-' && !this.displayValue.includes('-') && (this.displayValue === '' || e.target.selectionStart === 0))) return;

			e.preventDefault();
		},
	},
};
</script>

父组件

html 复制代码
<currency-input :value="addFormData.advancePaymentAmt" big-number :precision="2" @input="handleAmountInput($event, 'advancePaymentAmt')"></currency-input>
typescript 复制代码
function handleAmountInput(data: any, field: string, type?: string, cIndex?: number) {
	// if (type == 'navItem_total' || type == 'navItem') {
	// 	state.formData.prodNavs.forEach((fItem: any, fIndex: number) => {
	// 		if (fIndex == cIndex) fItem[field] = data;
	// 	});
	// } else {
	// 	state.formData[field] = data;
	// }
	state.formData[field] = data;
}
相关推荐
GISer_Jing5 分钟前
前端面试通关:Cesium+Three+React优化+TypeScript实战+ECharts性能方案
前端·react.js·面试
落霞的思绪1 小时前
CSS复习
前端·css
咖啡の猫3 小时前
Shell脚本-for循环应用案例
前端·chrome
百万蹄蹄向前冲5 小时前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
朝阳5816 小时前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路6 小时前
GeoTools 读取影像元数据
前端
ssshooter7 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
你的人类朋友7 小时前
【Node.js】什么是Node.js
javascript·后端·node.js
Jerry7 小时前
Jetpack Compose 中的状态
前端
dae bal8 小时前
关于RSA和AES加密
前端·vue.js