Vue3 + TypeScript + el-input 处理金额输入(只能输入数字、负号和小数点,最多两位小数,不能0开头,不能小数点开头,只能开头输入负号,只能输入一次负号和小数点)

特点:输入值、显示值、数据值不一致

比如:

输入值显示值数据值
-.0-0.00

// 金额输入失焦时,处理输入,包含但不限于-0、-0.、-0.0、-0.00、0.的情况,将输入的值转换为数字
const handleTotalBlur = (e: Event) => {
  const target = e.target as HTMLInputElement;

  // 处理输入-0、-0.、-0.0、-0.00、0.的情况,将输入的值转换为0
  // if (
  //   target.value === "-0" ||
  //   target.value === "-0." ||
  //   target.value === "-0.0" ||
  //   target.value === "-0.00" ||
  //   target.value === "0."
  // ) {
  //   target.value = "0";
  //   localCapitalInfo.capitalTotal = parseFloat(target.value);
  // }

  // 处理输入,将输入的值转换为数字
  if (target.value) {
    localCapitalInfo.capitalTotal = parseFloat(target.value);
  }
};

方法1:oninput 原生事件 + @blur

代码:复杂的正则表达式代码

                <!-- 方法1:oninput 原生事件 + @blur,复杂的正则表达式代码 -->
                <el-input
                  v-model="localCapitalInfo.capitalTotal"
                  oninput="value=value.replace(/[^\d.-]/g, ``).replace(/^(-?)0+(\d)/, `$1$2`).replace(/(?!^)-/g, ``).replace(/^(-?)(\.)/, `$10.`).replace(/(\..*)\./g, `$1`).replace(/^(-?\d*\.\d{0,2}).*/g, `$1`)"
                  @blur="handleTotalBlur"
                  clearable />

代码:易读的JavaScript代码(直接在这里写代码)

                <!-- 方法1:oninput 原生事件 + @blur,易读的JavaScript代码(直接在这里写代码) -->
                <el-input
                  v-model="localCapitalInfo.capitalTotal"
                  oninput="
                  let v = this.value;
  
                  // 1. 只允许数字、小数点、负号
                  v = v.replace(/[^\d.-]/g, '');
  
                  // 2. 处理负号:只能出现在开头,且只出现一次
                  let hasNegative = false;
                  if (v.includes('-')) {
                    // 检查负号是否在开头
                    if (v[0] === '-') {
                      hasNegative = true;
                      // 保留开头的负号,移除其他位置的负号
                      v = '-' + v.slice(1).replace(/-/g, '');
                    } else {
                      // 负号不在开头,移除所有负号
                      v = v.replace(/-/g, '');
                    }
                  }
  
                  // 3. 处理单独的小数点
                  if (v === '.') v = '0.';
                  if (v === '-.') v = '-0.';
  
                  // 4. 处理前导零:去除整数部分的前导零,但保留小数点和负数的情况
                  if (hasNegative) {
                    // 负数情况:-0.12 应该保留为 -0.12
                    // 只有当负号后面有多个0,且这些0后面不是小数点时,才去除前导零
                    // 例如:-0123 应该变成 -123
                    v = v.replace(/^(-?)0+(\d)/, '$1$2');
                  } else {
                    // 正数情况:0123 应该变成 123
                    v = v.replace(/^0+(\d)/, '$1');
                  }
  
                  // 5. 去除多余的小数点(只保留第一个)
                  const firstDot = v.indexOf('.');
                  if (firstDot !== -1) {
                    const beforeDot = v.substring(0, firstDot + 1);
                    const afterDot = v.substring(firstDot + 1).replace(/\./g, '');
                    v = beforeDot + afterDot;
                  }
  
                  // 6. 限制小数点后最多两位
                  const dotIndex = v.indexOf('.');
                  if (dotIndex !== -1) {
                    const integerPart = v.substring(0, dotIndex);
                    const decimalPart = v.substring(dotIndex + 1, dotIndex + 3);
                    v = integerPart + '.' + decimalPart;
                  }
  
                  // 7. 特殊情况处理:如果只有负号或负号加0,保留它们
                  if (v === '-' || v === '-0') {
                    this.value = v;
                    return;
                  }
  
                  // 8. 处理以0开头的非小数情况
                  if (v.length > 1 && v[0] === '0' && v[1] !== '.') {
                    v = v.substring(1);
                  }
  
                  this.value = v;
                  "
                  @blur="handleTotalBlur"
                  clearable />

代码:易读的JavaScript代码(使用常量)

1、创建常量 + 统一导出

src\constants\ExecutionCode.constants.ts

// 执行代码类常量

/**
 * 金额输入框数输入时执行的代码,遇到需转义的符号(如反斜杠 \),需要使用两个反斜杠(\\)处理反斜杠(\)
 */
// export const TOTAL_INPUT_EXECUTE_CODE = `
//   let v = this.value;

//   // 1. 只允许数字、小数点、负号
//   v = v.replace(/[^\\d.-]/g, '');

//   // 2. 处理负号:只能出现在开头,且只出现一次
//   let hasNegative = false;
//   if (v.includes('-')) {
//     // 检查负号是否在开头
//     if (v[0] === '-') {
//       hasNegative = true;
//       // 保留开头的负号,移除其他位置的负号
//       v = '-' + v.slice(1).replace(/-/g, '');
//     } else {
//       // 负号不在开头,移除所有负号
//       v = v.replace(/-/g, '');
//     }
//   }

//   // 3. 处理单独的小数点
//   if (v === '.') v = '0.';
//   if (v === '-.') v = '-0.';

//   // 4. 处理前导零:去除整数部分的前导零,但保留小数点和负数的情况
//   if (hasNegative) {
//     // 负数情况:-0.12 应该保留为 -0.12
//     // 只有当负号后面有多个0,且这些0后面不是小数点时,才去除前导零
//     // 例如:-0123 应该变成 -123
//     v = v.replace(/^(-?)0+(\\d)/, '$1$2');
//   } else {
//     // 正数情况:0123 应该变成 123
//     v = v.replace(/^0+(\\d)/, '$1');
//   }

//   // 5. 去除多余的小数点(只保留第一个)
//   const firstDot = v.indexOf('.');
//   if (firstDot !== -1) {
//     const beforeDot = v.substring(0, firstDot + 1);
//     const afterDot = v.substring(firstDot + 1).replace(/\\./g, '');
//     v = beforeDot + afterDot;
//   }

//   // 6. 限制小数点后最多两位
//   const dotIndex = v.indexOf('.');
//   if (dotIndex !== -1) {
//     const integerPart = v.substring(0, dotIndex);
//     const decimalPart = v.substring(dotIndex + 1, dotIndex + 3);
//     v = integerPart + '.' + decimalPart;
//   }

//   // 7. 特殊情况处理:如果只有负号或负号加0,保留它们
//   if (v === '-' || v === '-0') {
//     this.value = v;
//     return;
//   }

//   // 8. 处理以0开头的非小数情况
//   if (v.length > 1 && v[0] === '0' && v[1] !== '.') {
//     v = v.substring(1);
//   }

//   this.value = v;
// `;

/**
 * 金额输入框数输入时执行的代码,使用 String.raw 可以原样处理字符串,不解析转义序列,对于正则表达式,String.raw 非常有用
 */
export const TOTAL_INPUT_EXECUTE_CODE = String.raw`
  let v = this.value;
  
  // 1. 只允许数字、小数点、负号
  v = v.replace(/[^\d.-]/g, '');
  
  // 2. 处理负号:只能出现在开头,且只出现一次
  let hasNegative = false;
  if (v.includes('-')) {
    // 检查负号是否在开头
    if (v[0] === '-') {
      hasNegative = true;
      // 保留开头的负号,移除其他位置的负号
      v = '-' + v.slice(1).replace(/-/g, '');
    } else {
      // 负号不在开头,移除所有负号
      v = v.replace(/-/g, '');
    }
  }
  
  // 3. 处理单独的小数点
  if (v === '.') v = '0.';
  if (v === '-.') v = '-0.';
  
  // 4. 处理前导零:去除整数部分的前导零,但保留小数点和负数的情况
  if (hasNegative) {
    // 负数情况:-0.12 应该保留为 -0.12
    // 只有当负号后面有多个0,且这些0后面不是小数点时,才去除前导零
    // 例如:-0123 应该变成 -123
    v = v.replace(/^(-?)0+(\d)/, '$1$2');
  } else {
    // 正数情况:0123 应该变成 123
    v = v.replace(/^0+(\d)/, '$1');
  }
  
  // 5. 去除多余的小数点(只保留第一个)
  const firstDot = v.indexOf('.');
  if (firstDot !== -1) {
    const beforeDot = v.substring(0, firstDot + 1);
    const afterDot = v.substring(firstDot + 1).replace(/\./g, '');
    v = beforeDot + afterDot;
  }
  
  // 6. 限制小数点后最多两位
  const dotIndex = v.indexOf('.');
  if (dotIndex !== -1) {
    const integerPart = v.substring(0, dotIndex);
    const decimalPart = v.substring(dotIndex + 1, dotIndex + 3);
    v = integerPart + '.' + decimalPart;
  }
  
  // 7. 特殊情况处理:如果只有负号或负号加0,保留它们
  if (v === '-' || v === '-0') {
    this.value = v;
    return;
  }
  
  // 8. 处理以0开头的非小数情况
  if (v.length > 1 && v[0] === '0' && v[1] !== '.') {
    v = v.substring(1);
  }
  
  this.value = v;
`;

src\constants\index.ts

export * from "./ExecutionCode.constants";

2、使用常量

src\views\capital\CapitalInfo.vue

import { TOTAL_INPUT_EXECUTE_CODE } from "@/constants";

                <!-- 方法1:oninput 原生事件 + @blur,易读的JavaScript代码(使用常量) -->
                <el-input
                  v-model="localCapitalInfo.capitalTotal"
                  :oninput="TOTAL_INPUT_EXECUTE_CODE"
                  @blur="handleTotalBlur"
                  clearable />

方法2:@input 事件 + @blur

代码:

// 金额显示,用于替换绑定的金额字段 localCapitalInfo.capitalTotal
const capitalTotalDisplay = ref("");

// 处理金额输入时,只能输入数字、负号和小数点,最多两位小数,不能0开头,不能小数点开头,只能开头输入负号,只能输入一次负号和小数点
const handleTotalInput = (value: string) => {
  let v = value;

  // 如果值为空,设置为空字符串
  if (v === "") {
    localCapitalInfo.capitalTotal = 0;
    capitalTotalDisplay.value = "";
    return;
  }

  // 1. 只允许数字、小数点、负号
  v = v.replace(/[^\d.-]/g, "");

  // 2. 处理负号:只能出现在开头,且只出现一次
  let hasNegative = false;
  if (v.includes("-")) {
    // 检查负号是否在开头
    if (v[0] === "-") {
      hasNegative = true;
      // 保留开头的负号,移除其他位置的负号
      v = "-" + v.slice(1).replace(/-/g, "");
    } else {
      // 负号不在开头,移除所有负号
      v = v.replace(/-/g, "");
    }
  }

  // 3. 处理单独的小数点
  if (v === ".") v = "0.";
  if (v === "-.") v = "-0.";

  // 4. 处理前导零:去除整数部分的前导零,但保留小数点和负数的情况
  if (hasNegative) {
    v = v.replace(/^(-?)0+(\d)/, "$1$2");
  } else {
    v = v.replace(/^0+(\d)/, "$1");
  }

  // 5. 去除多余的小数点(只保留第一个)
  const firstDot = v.indexOf(".");
  if (firstDot !== -1) {
    const beforeDot = v.substring(0, firstDot + 1);
    const afterDot = v.substring(firstDot + 1).replace(/\./g, "");
    v = beforeDot + afterDot;
  }

  // 6. 限制小数点后最多两位
  const dotIndex = v.indexOf(".");
  if (dotIndex !== -1) {
    const integerPart = v.substring(0, dotIndex);
    const decimalPart = v.substring(dotIndex + 1, dotIndex + 3);
    v = integerPart + "." + decimalPart;
  }

  // 7. 特殊情况处理:如果只有负号或负号加0,保留它们
  // 对于这些中间状态,我们保持字符串形式
  const specialCases = ["-", "-0", "-0.", "-0.0", "-0.00"];
  if (specialCases.includes(v)) {
    // 保持为字符串输入
    capitalTotalDisplay.value = v;
    // 但绑定的数字值设为0
    localCapitalInfo.capitalTotal = 0;
    return;
  }

  // 8. 处理以0开头的非小数情况
  if (v.length > 1 && v[0] === "0" && v[1] !== ".") {
    v = v.substring(1);
  }

  // 9. 更新金额显示(字符串)
  capitalTotalDisplay.value = v;

  // 10. 更新金额(数字值,如果可以转换为数字)
  if (v === "") {
    localCapitalInfo.capitalTotal = 0;
  } else {
    // 尝试转换为数字
    const num = parseFloat(v);
    if (!isNaN(num)) {
      localCapitalInfo.capitalTotal = num;
    } else {
      // 如果无法转换,设为0
      localCapitalInfo.capitalTotal = 0;
    }
  }
};

                <!-- 方法2:@input 事件 + @blur -->
                <el-input v-model="capitalTotalDisplay" @input="handleTotalInput" @blur="handleTotalBlur" clearable />

方法3:使用计算属性 computed + @blur 【暂无法实现】

代码:

// 计算属性:金额输入
const totalInput = computed({
  get(): string {
    const value = localCapitalInfo.capitalTotal;
    // 如果是数字,转换为字符串;如果是空值,返回空字符串
    if (value === undefined || value === null || value === 0) {
      return "";
    }
    return value.toString();
  },
  set(value: string): void {
    const formattedValue = formatTotalInput(value);

    // 更新到响应式数据
    if (formattedValue === "" || formattedValue === "-") {
      localCapitalInfo.capitalTotal = 0;
    } else {
      const numValue = parseFloat(formattedValue);
      localCapitalInfo.capitalTotal = isNaN(numValue) ? 0 : numValue;
    }
  }
});

// 格式化输入的金额
const formatTotalInput = (value: string): string => {
  let v = value;

  // 如果值为空,设置为空字符串
  if (!v) {
    return "";
  }

  // 1. 只允许数字、小数点、负号
  v = v.replace(/[^\d.-]/g, "");

  // 2. 处理负号:只能出现在开头,且只出现一次
  let hasNegative = false;
  if (v.includes("-")) {
    // 检查负号是否在开头
    if (v[0] === "-") {
      hasNegative = true;
      // 保留开头的负号,移除其他位置的负号
      v = "-" + v.slice(1).replace(/-/g, "");
    } else {
      // 负号不在开头,移除所有负号
      v = v.replace(/-/g, "");
    }
  }

  // 3. 处理单独的小数点
  if (v === ".") v = "0.";
  if (v === "-.") v = "-0.";

  // 4. 处理前导零:去除整数部分的前导零,但保留小数点和负数的情况
  if (hasNegative) {
    v = v.replace(/^(-?)0+(\d)/, "$1$2");
  } else {
    v = v.replace(/^0+(\d)/, "$1");
  }

  // 5. 去除多余的小数点(只保留第一个)
  const firstDot = v.indexOf(".");
  if (firstDot !== -1) {
    const beforeDot = v.substring(0, firstDot + 1);
    const afterDot = v.substring(firstDot + 1).replace(/\./g, "");
    v = beforeDot + afterDot;
  }

  // 6. 限制小数点后最多两位
  const dotIndex = v.indexOf(".");
  if (dotIndex !== -1) {
    const integerPart = v.substring(0, dotIndex);
    const decimalPart = v.substring(dotIndex + 1, dotIndex + 3);
    v = integerPart + "." + decimalPart;
  }

  // 7. 特殊情况处理:如果只有负号或负号加0,保留它们

  // 8. 处理以0开头的非小数情况
  if (v.length > 1 && v[0] === "0" && v[1] !== ".") {
    v = v.substring(1);
  }

  // 9. 返回格式化后的输入内容
  return v;
};

                <!-- 方法3:使用计算属性 computed + @blur,暂无法实现 -->
                <el-input v-model="totalInput" @blur="handleTotalBlur" clearable />

方法4:自定义指令 + @blur

1、创建指令 + 统一导出

src\directives\totalInputDirective.ts

import type { Directive } from "vue";

// 使用 WeakMap 存储事件处理器,避免直接在 DOM 元素上添加自定义属性
const handlerMap = new WeakMap<HTMLInputElement, (e: Event) => void>();

// 格式化输入的金额,需定义在指令外部
const formatTotalInput = (value: string): string => {
  let v = value;

  // 如果值为空,设置为空字符串
  if (!v) {
    return "";
  }

  // 1. 只允许数字、小数点、负号
  v = v.replace(/[^\d.-]/g, "");

  // 2. 处理负号:只能出现在开头,且只出现一次
  let hasNegative = false;
  if (v.includes("-")) {
    // 检查负号是否在开头
    if (v[0] === "-") {
      hasNegative = true;
      // 保留开头的负号,移除其他位置的负号
      v = "-" + v.slice(1).replace(/-/g, "");
    } else {
      // 负号不在开头,移除所有负号
      v = v.replace(/-/g, "");
    }
  }

  // 3. 处理单独的小数点
  if (v === ".") v = "0.";
  if (v === "-.") v = "-0.";

  // 4. 处理前导零:去除整数部分的前导零,但保留小数点和负数的情况
  if (hasNegative) {
    v = v.replace(/^(-?)0+(\d)/, "$1$2");
  } else {
    v = v.replace(/^0+(\d)/, "$1");
  }

  // 5. 去除多余的小数点(只保留第一个)
  const firstDot = v.indexOf(".");
  if (firstDot !== -1) {
    const beforeDot = v.substring(0, firstDot + 1);
    const afterDot = v.substring(firstDot + 1).replace(/\./g, "");
    v = beforeDot + afterDot;
  }

  // 6. 限制小数点后最多两位
  const dotIndex = v.indexOf(".");
  if (dotIndex !== -1) {
    const integerPart = v.substring(0, dotIndex);
    const decimalPart = v.substring(dotIndex + 1, dotIndex + 3);
    v = integerPart + "." + decimalPart;
  }

  // 7. 特殊情况处理:如果只有负号或负号加0,保留它们

  // 8. 处理以0开头的非小数情况
  if (v.length > 1 && v[0] === "0" && v[1] !== ".") {
    v = v.substring(1);
  }

  // 9. 返回格式化后的输入内容
  return v;
};

/**
 * 自定义指令:金额输入指令,只能输入数字、负号和小数点,最多两位小数,不能0开头,不能小数点开头,只能开头输入负号,只能输入一次负号和小数点
 */
export const totalInputDirective: Directive = {
  /**
   * 指令挂载到元素上时的钩子函数
   * @param el - 指令绑定的DOM元素
   */
  mounted(el: HTMLElement | HTMLInputElement) {
    // 找到 input 元素
    let input: HTMLInputElement | null = null;

    if (el.tagName === "INPUT") {
      input = el as HTMLInputElement;
    } else {
      input = el.querySelector && el.querySelector("input");
    }

    if (!input) return;

    // 处理输入事件的函数
    const handler = (e: Event) => {
      const target = e.target as HTMLInputElement;

      // 获取输入的值
      const inputValue = target.value;

      const value = formatTotalInput(inputValue);

      if (value !== target.value) {
        const oldValue = target.value;
        target.value = value;

        // 如果值发生了变化,触发input事件以确保Vue的数据绑定更新
        if (oldValue !== value) {
          target.dispatchEvent(new Event("input", { bubbles: true }));
        }
      }
    };

    // 监听输入事件
    input.addEventListener("input", handler);

    // 使用 WeakMap 存储处理器引用,以便后续移除
    handlerMap.set(input, handler);
  },

  /**
   * 指令从元素解绑时的钩子函数
   * 清理事件监听器以避免内存泄漏
   * @param el - 指令绑定的DOM元素
   */
  unmounted(el: HTMLElement | HTMLInputElement) {
    let input: HTMLInputElement | null = null;

    if (el.tagName === "INPUT") {
      input = el as HTMLInputElement;
    } else {
      input = el.querySelector && el.querySelector("input");
    }

    if (input) {
      const storedHandler = handlerMap.get(input);
      if (storedHandler) {
        // 移除事件监听器以防止内存泄漏
        input.removeEventListener("input", storedHandler);
        handlerMap.delete(input);
      }
    }
  }
};

src\directives\index.ts

export * from "./totalInputDirective";

2、注册指令

2.1、全局注册指令(导入指令 + 安装指令)

src\main.ts

// 使用命名导入,全局引入自定义指令:金额输入指令
import { totalInputDirective } from "@/directives";

// 创建 Vue 应用实例
const app = createApp(App);

// 安装自定义指令,金额输入指令 totalInput,在模板中使用 v-total-input 指令
app.directive("totalInput", totalInputDirective);

// 将 Vue 应用实例挂载到 DOM 中的一个指定容器上,从而启动 Vue 应用
app.mount("#app");

2.2、局部注册指令(导入指令 + 定义指令)

src\views\capital\CapitalInfo.vue

import { totalInputDirective } from "@/directives";

// 定义指令:金额输入指令,规范以v开头,在模板中使用 v-total-input 指令
const vTotalInput = totalInputDirective ;

3、使用指令

src\views\capital\CapitalInfo.vue

                <!-- 方法4:自定义指令 + @blur -->
                <el-input v-model="localCapitalInfo.capitalTotal" v-total-input @blur="handleTotalBlur" clearable />

方法5:组件方式

代码:

1、创建组件 + 统一导出

src\components\base\BaseTotalInput.vue

<script setup lang="ts">
/**
 * 金额输入框组件
 * 功能:只能输入数字、负号和小数点,最多两位小数
 * 不能0开头,不能小数点开头,只能开头输入负号,只能输入一次负号和小数点
 */
defineOptions({
  name: "BaseTotalInput"
});

import { ref, watch, nextTick } from "vue";

const props = defineProps<{
  modelValue?: number | string;
}>();

const emit = defineEmits<{
  "update:modelValue": [value: number];
}>();

// 内部显示的字符串值
const displayValue = ref("");

// 监听父组件传入的值变化
watch(
  () => props.modelValue,
  (newVal) => {
    if (newVal !== undefined && newVal !== null) {
      displayValue.value = String(newVal);
    } else {
      displayValue.value = "";
    }
  },
  { immediate: true }
);

// 特殊中间状态
const specialCases = ["-", "-0", "-0.", "-0.0", "-0.00"];

// 格式化输入的金额
const formatTotalInput = (value: string): string => {
  let v = value;

  // 如果值为空,返回空字符串
  if (v === "") {
    return "";
  }

  // 1. 只允许数字、小数点、负号
  v = v.replace(/[^\d.-]/g, "");

  // 2. 处理负号:只能出现在开头,且只出现一次
  let hasNegative = false;
  if (v.includes("-")) {
    // 检查负号是否在开头
    if (v[0] === "-") {
      hasNegative = true;
      // 保留开头的负号,移除其他位置的负号
      v = "-" + v.slice(1).replace(/-/g, "");
    } else {
      // 负号不在开头,移除所有负号
      v = v.replace(/-/g, "");
    }
  }

  // 3. 处理单独的小数点
  if (v === ".") v = "0.";
  if (v === "-.") v = "-0.";

  // 4. 处理前导零:去除整数部分的前导零,但保留小数点和负数的情况
  if (hasNegative) {
    v = v.replace(/^(-?)0+(\d)/, "$1$2");
  } else {
    v = v.replace(/^0+(\d)/, "$1");
  }

  // 5. 去除多余的小数点(只保留第一个)
  const firstDot = v.indexOf(".");
  if (firstDot !== -1) {
    const beforeDot = v.substring(0, firstDot + 1);
    const afterDot = v.substring(firstDot + 1).replace(/\./g, "");
    v = beforeDot + afterDot;
  }

  // 6. 限制小数点后最多两位
  const dotIndex = v.indexOf(".");
  if (dotIndex !== -1) {
    const integerPart = v.substring(0, dotIndex);
    const decimalPart = v.substring(dotIndex + 1, dotIndex + 3);
    v = integerPart + "." + decimalPart;
  }

  // 7. 处理以0开头的非小数情况
  if (v.length > 1 && v[0] === "0" && v[1] !== ".") {
    v = v.substring(1);
  }

  return v;
};

// 处理输入事件
const handleInput = (value: string) => {
  const formatted = formatTotalInput(value);

  // 更新显示值
  displayValue.value = formatted;

  // 如果是特殊中间状态,emit 0
  if (specialCases.includes(formatted)) {
    emit("update:modelValue", 0);
    return;
  }

  // 如果为空字符串,emit 0
  if (formatted === "") {
    emit("update:modelValue", 0);
    return;
  }

  // 尝试转换为数字
  const num = parseFloat(formatted);
  if (!isNaN(num)) {
    emit("update:modelValue", num);
  } else {
    // 如果无法转换,emit 0
    emit("update:modelValue", 0);
  }
};

// 处理失焦事件
const handleBlur = () => {
  // 如果是特殊中间状态,转换为0
  if (specialCases.includes(displayValue.value) || displayValue.value === "0.") {
    displayValue.value = "0";
    emit("update:modelValue", 0);
    return;
  }

  // 如果为空,设为0
  if (displayValue.value === "") {
    displayValue.value = "0";
    emit("update:modelValue", 0);
    return;
  }

  // 尝试转换为数字并格式化显示
  const num = parseFloat(displayValue.value);
  if (!isNaN(num)) {
    displayValue.value = num.toString();
    emit("update:modelValue", num);
  } else {
    displayValue.value = "0";
    emit("update:modelValue", 0);
  }
};

// 处理清空事件
const handleClear = () => {
  displayValue.value = "";
  emit("update:modelValue", 0);
};
</script>

<template>
  <el-input
    :model-value="displayValue"
    @input="handleInput"
    @blur="handleBlur"
    @clear="handleClear"
    clearable
    v-bind="$attrs" />
</template>

<style scoped lang="scss"></style>

src\components\index.ts

export { default as BaseTotalInput } from "./base/BaseTotalInput.vue";

2、使用组件

src\views\capital\CapitalInfo.vue

import { BaseTotalInput } from "@/components";

                <!-- 方法5:组件方式 -->
                <BaseTotalInput v-model="localCapitalInfo.capitalTotal" clearable />

效果:

键盘输入

类型输入内容生成内容失焦后
常规000
常规0.10.10.1
常规0.010.010.01
常规123.45123.45123.45
常规-0.1-0.1-0.1
常规-123.45-123.45-123.45
0结尾0.00.00
0结尾0.000.000
0结尾0.100.100.1
0结尾-0.10-0.10-0.1
0开头0000
0开头0111
多0开头00111
多0开头00.10.10.1
特殊情况,负0-0-00
特殊情况,负0点-0.-0.0
特殊情况,负0点0-0.0-0.00
特殊情况,负0点00-0.00-0.000
特殊情况,负点0-.0-0.00
特殊情况,负点1-.1-0.1-0.1
特殊情况,负点01-.01-0.01-0.01
特殊情况,负号--NaN
特殊情况,多个负号----NaN
小数点开头.00.00
小数点开头.10.10.1
小数点开头.010.010.01
小数点结尾0.0.0
小数点结尾1.1.1
包含非法输入a111
包含非法输入1a11
包含非法输入1.a21.21.2
全部非法输入abc
全部非法输入*

拷贝输入

类型输入内容

生成内容,

失焦后
常规000
常规0.10.10.1
常规0.010.010.01
常规123.45123.45123.45
常规-0.1-0.1-0.1
常规-123.45-123.45-123.45
0结尾0.00.00
0结尾0.000.000
0结尾0.100.100.1
0结尾-0.10-0.10-0.1
0开头0000
0开头0111
多0开头00111
多0开头00.10.10.1
特殊情况,负0-0-00
特殊情况,负0点-0.-0.0
特殊情况,负0点0-0.0-0.00
特殊情况,负0点00-0.00-0.000
特殊情况,负点0-.0-.00
特殊情况,负点1-.1-.1-0.1
特殊情况,负点01-.01-.01-0.01
特殊情况,负号--NaN
特殊情况,多个负号----NaN
小数点开头.0.00
小数点开头.1.10.1
小数点开头.01.010.01
小数点结尾0.0.0
小数点结尾1.1.1
包含非法输入a111
包含非法输入1a11
包含非法输入1.a21.21.2
全部非法输入abc
全部非法输入*

其他:

支持.01

                <!-- 处理金额输入(只能输入数字、负号和小数点,最多两位小数,不能0开头,只能开头输入负号,只能输入一次负号和小数点),支持.01 -->
                <!-- 方法1:oninput 原生事件 + @blur -->
                <el-input
                  v-model="localCapitalInfo.capitalTotal"
                  oninput="value=value.replace(/[^\d.-]/g, ``).replace(/^(-?)0+(\d)/, `$1$2`).replace(/(?!^)-/g, ``).replace(/(\..*)\./g, `$1`).replace(/^(-?\d*\.\d{0,2}).*/g, `$1`)"
                  @blur="handleTotalBlur"
                  clearable />

效果:

键盘输入

类型输入内容生成内容失焦后
小数点开头.01.010.01

拷贝输入

类型输入内容生成内容失焦后
小数点开头.01.010.01
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值