vue2+el-input封装金额输入框

416 阅读1分钟

vue封装el-input组件,实现一个金额输入框,失去焦点时展示千分位金额,获取焦点时去除千分位,允许输入负数。

  1. 新建两个js文件,分别对输入框输入格式进行校验限制,格式化金额。
//  src/utils/inputNumber.js
// 此方法用来实现将一个字符串通过replace方法,格式化为普通数字格式(包括正负整数、正负浮点数都支持)
export const inputNumber = (val) => {
  if (val === "-" || !val) return val;
  if (val === ".") return "";
  const reg1 = /[^\d|\-|\.]/g;//限制只能输入 - . 数字
  const reg2 = /(\d|\.)\-+/g;
  const reg3 = /\-{2,}/g; //匹配输入多个-的情况

  const str = val
    .replace(reg1, "")
    .replace(reg2, "$1")
    .replace(reg3, "-")
    .replace("-.", "-");
  const pointArr = str.split(".");
  pointArr[0] = parseInt(pointArr[0]); //避免开头输入多个0的情况
  let value = "";
  if (pointArr.length > 1) {
    pointArr.forEach((item, index) => {
      value = value + item;
      if (!index) {
        value = value + ".";
      }
    });
  } else {
    value = pointArr[0].toString();
  }
  return value;
};

// src/utils/formatMoney.js

/**
 * 格式化金额
 * @param money { String / Number } 金额
 * @param format { String } a-b:限制输入的字符长度,a:整数长度,b:小数长度
 * @returns {string|null}
 */
export const formatMoney = (money, format) => {
  if (typeof money === "number") {
    money = money.toString();
  }
  if (money === "-" || !money) return money;
  if (!format) format = "15-2";
  const intNum = Number(format.split("-")[0]);
  const decimalNum = Number(format.split("-")[1]);
  const moneyArr = money.split(".");
  moneyArr[0] =
    moneyArr[0].length > intNum ? moneyArr[0].substr(0, intNum) : moneyArr[0];
  if (moneyArr[1]) {
    moneyArr[1] =
      moneyArr[1].length > decimalNum
        ? moneyArr[1].substr(0, decimalNum)
        : moneyArr[1];
  }
  money = moneyArr.join(".");
  const isNegativeNum = money.startsWith("-");
  const pointPosition = money.indexOf(".");
  const decimal = pointPosition !== -1 ? money.substr(pointPosition) : "";
  const integer = Math.abs(parseInt(money).toString()).toString();
  const integerArrReverse = integer.split("").reverse().join("");
  const moneyStringify = `${isNegativeNum ? "-" : ""}${integerArrReverse
    .replace(/(\d{3})(?=\d)/g, "$1,")
    .split("")
    .reverse()
    .join("")}${decimal}`;
  return moneyStringify;
};

  1. 新建money-input组件
// src/components/money-input.vue

<template>
  <el-input
    v-model="inputValue"
    v-bind="$attrs"
    :maxlength="maxlength"
    @input="handleInput"
    @focus="handleFocus"
    @blur="handleBlur"
    @change="handleChange"
  >
    <template slot="append">
      <slot name="append"></slot>
    </template>
  </el-input>
</template>

<script>
import { inputNumber } from "@/utils/inputNumber";
import { formatMoney } from "@/utils/formatMoney";

export default {
  props: {
    value: {
      type: [String, Number],
      default: "",
    },
    // 金额位数格式(a-b);a:整数位数;b:小数位数
    format: {
      type: String,
      default: "15-2",
    },
  },
  data() {
    return {
      inputValue: "",
      inputing: false,
    };
  },
  computed: {
    integerNum() {
      return Number(this.format.split("-")[0]);
    },
    decimalNum() {
      return Number(this.format.split("-")[1]);
    },
    maxlength() {
      return (
        this.integerNum +
        (this.decimalNum > 0 ? this.decimalNum + 1 : this.decimalNum)
      );
    },
  },
  watch: {
    value: {
      immediate: true,
      handler(n) {
        if (!n) {
          this.inputValue = n;
          return;
        }
        if (this.inputing) {
          this.inputValue = n;
        } else {
          this.inputValue = formatMoney(inputNumber(n.toString()), this.format);
        }
      },
    },
  },
  methods: {
    handleInput(val) {
      this.inputing = true;
      let money = inputNumber(val);
      const format = this.format;
      const moneyArr = money.split(".");
      moneyArr[0] =
        moneyArr[0].length > this.integerNum
          ? moneyArr[0].substr(0, this.integerNum)
          : moneyArr[0];
      if (moneyArr[1]) {
        moneyArr[1] =
          moneyArr[1].length > this.decimalNum
            ? moneyArr[1].substr(0, this.decimalNum)
            : moneyArr[1];
      }
      money = moneyArr.join(".");
      this.inputValue = money;
      let value = "";
      if (money === "-" || money === ".") {
        value = "";
      } else if (money !== "") {
        value = Number(inputNumber(money));
      }
      this.$emit("input", value);
    },
    handleChange(val) {
      this.inputing = true;
      this.$emit("change", Number(val.replaceAll(",", "")));
    },
    handleBlur(e) {
      this.inputing = false;
      this.inputValue = formatMoney(inputNumber(e.target.value), this.format);
      this.$emit("blur", e);
    },
    handleFocus(e) {
      this.inputing = true;
      this.inputValue = inputNumber(this.inputValue);
      this.$emit("focus", e);
    },
  },
};
</script>

  1. 全局注册组件
main.js
import MoneyInput from "./components/moneyInput.vue";
Vue.component("MoneyInput", MoneyInput);
  1. 页面使用
<template>
  <div id="app">
    <money-input v-model="value" placeholder="请输入金额" @input="handleInput"></money-input>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      value: "",
    };
  },
  methods: {
    handleInput(val) {
      console.log( val,this.value);
    },
  },
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>