vue封装el-input组件,实现一个金额输入框,失去焦点时展示千分位金额,获取焦点时去除千分位,允许输入负数。
- 新建两个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;
};
- 新建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>
- 全局注册组件
main.js
import MoneyInput from "./components/moneyInput.vue";
Vue.component("MoneyInput", MoneyInput);
- 页面使用
<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>