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;
}
相关推荐
吃瓜群众i1 小时前
理解Javascript闭包
前端·javascript
安大桃子1 小时前
Mapbox GL + Deck.gl 三维实战:Mapbox 加载 Tileset3D 倾斜摄影模型
前端·webgl
yede1 小时前
多行文本省略号显示,更多按钮展开全部
前端
就是我1 小时前
React 应用性能优化实战
前端·react.js·性能优化
G扇子1 小时前
深入解析XSS攻击:从原理到防御的全方位指南
前端·安全
Blucas1 小时前
《深入 PageSpy》二:入门指南
javascript·前端框架
snakeshe10101 小时前
入解析React性能优化策略:eagerState的工作原理
前端
六边形6661 小时前
Vue中的 ref、toRef 和 toRefs 有什么区别
前端·vue.js·面试
kovli1 小时前
红宝书第十八讲:详解JavaScript的async/await与错误处理
前端·javascript
前端付豪1 小时前
🚀 React 应用国际化实战:深入掌握 react-i18next 的高级用法
前端·react.js·架构