Files
hht-tongbo-two/components/NumberInput.vue
2025-06-13 17:58:39 +08:00

136 lines
3.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<input
type="number"
:value="displayValue"
@input="handleInput"
@blur="handleBlur"
:class="inputClass"
/>
</template>
<script>
export default {
name: "NumberInput",
props: {
value: [Number, String],
inputClass: {
type: String,
default: ''
},
// 输入模式integer(纯整数), decimal(纯小数), mixed(混合)
mode: {
type: String,
default: "mixed",
validator: (v) => ["integer", "decimal", "mixed"].includes(v),
},
// 小数位数限制
decimalLength: {
type: Number,
default: 2,
},
// 最小值
min: {
type: Number,
default: 0,
},
// 最大值
max: {
type: Number,
default: Infinity,
},
},
data() {
return {
displayValue: this.value?.toString() || "",
};
},
watch: {
value(newVal) {
this.displayValue = newVal?.toString() || "";
},
},
methods: {
handleInput(e) {
let value = e.detail.value;
// 1. 过滤非法字符
let filtered = value.replace(/[^\d.]/g, "");
// 2. 处理多余的小数点
if (this.mode === "integer") {
filtered = filtered.replace(/\./g, ""); // 整数模式删除所有小数点
} else {
const firstDotIndex = filtered.indexOf(".");
if (firstDotIndex !== -1) {
// 只保留第一个小数点
filtered =
filtered.substring(0, firstDotIndex + 1) +
filtered.substring(firstDotIndex + 1).replace(/\./g, "");
}
}
// 3. 处理前导0
if (filtered.startsWith("0") && filtered.length > 1 && !filtered.startsWith("0.")) {
filtered = filtered.replace(/^0+/, "0").replace(/^0([^.])/, "$1");
}
// 4. 处理开头的小数点
if (filtered.startsWith(".")) {
if (this.mode === "integer") {
filtered = "";
} else {
filtered = "0" + filtered;
}
}
this.displayValue = filtered;
},
handleBlur() {
let value = this.displayValue;
// 空值处理
if (value === "" || value === ".") {
this.$emit("input", "");
return;
}
// 处理结尾的小数点
if (value.endsWith(".")) {
value = value.slice(0, -1);
}
// 转换为数字
const numValue = Number(value);
// 小数位数处理
let processedValue = value;
if (this.mode !== "integer" && value.includes(".")) {
const parts = value.split(".");
if (parts[1].length > this.decimalLength) {
processedValue = `${parts[0]}.${parts[1].slice(0, this.decimalLength)}`;
}
}
// 范围校验
let finalNum = Number(processedValue);
if (finalNum < this.min) finalNum = this.min;
if (finalNum > this.max) finalNum = this.max;
// 更新值
this.displayValue = finalNum.toString();
this.$emit("input", finalNum);
},
},
};
</script>
<style scoped>
.number-input {
border: 1px solid #ddd;
padding: 8px 12px;
border-radius: 4px;
font-size: 14px;
}
</style>