新建limitNumber.js文件
// limitNumber.js
/*
* 自定义指令限制数字的输入范围以及允许的小数位数
* 如果最后的输入结果为 - 或者 . 在回车或者失焦后会变成 ''
* 当输入 -.5 或者 .5 的时候会自动补充0 变成 -0.5 或者 0.5
* 允许输入中文 。 会自动变成 .
* 如果以 . 结尾,比如 5. 会自动变成 5
* 如果中间出现 - 号如何处理,有两种处理,只需打开相应的注释即可
* 1. 如果输入4-5 则不允许输入- 变成45
* 2. 如果输入 4-5 自动变成 -45
* 最后输入框的绑定值类型是 string 类型
* v-limit-number="{
min: -100, 限制输入的最小值
max: 100, 限制输入的最大值
decimal:3 限制输入的小数点几位
}"
*/
export default (app) => {
app.directive('limitNumber', {
mounted(el, binding) {
const decimal= binding.value.decimal || 0;
const min= binding.value.min||0
el.handlerInput = function (event) {
let input = event.target;
let value = input.value;
let oldValue = input.value;
// 移除非数字、负号、小数点的字符
value = value.replace(/[^-\d.。]/g, '')
// 连续的两个 - 换成一个 -
.replace(/-{2,}/g, '-')
// 处理负号位置,确保只有一个负号
.replace(/(\d+)?-+(\d+)?/, (_, num1, num2) => { // 当有 - 符号出现时候
if (num1 === undefined) {
return '-'+(num2||'');
} else {
// return (num1||'') + (num2||''); // 如果输入4-5 则不允许输入- 变成45
return '-'+(num1||'') + (num2||''); // 如果输入 4-5 自动变成 -45
}
})
.replace(/。/g, '.') // 将中文。转换为.
.replace(/\.{2,}/g, '.') // 连续的两个 . 换成一个 .
.replace('.', '$#$')
.replace(/\./g, '')
.replace('$#$', '.') // 只允许出现一次 .
.replace('-', '$#$')
.replace(/-/g, '')
.replace('$#$', '-'); // 只允许出现一次 -
value = value.replace(/(?<=^-?)(\.\d+)|[^-\d.]/g, match => {
// 如果匹配到的是小数点和数字,且小数点后只有一个数字,补充零
if (match.startsWith('.') && match.length === 2) {
return '0' + match;
}
return match;
});
// 处理小数点的位置,确保只有一个小数点且小数位数不超过指定值
let decimalIndex = value.indexOf('.');
if (decimalIndex > -1) {
if(decimal){
let decimalPart = value.substring(decimalIndex + 1);
if (decimalPart.length > decimal) {
decimalPart = decimalPart.substring(0, decimal);
value = value.substring(0, decimalIndex + 1) + decimalPart;
}
}else{
value = value.substring(0, decimalIndex);
}
}
// 转换为数字之后不为NaN
if(!isNaN(Number(value))){
if (+value > binding.value.max || +value < min) {
// 处理最大值和最小值
value = Math.min(Math.max(value, min), binding.value.max);
}
}
// 判断是否需要更新,避免进入死循环
if (oldValue.toString() !== value.toString()) {
input.value = value;
// 手动触发 input 事件以确保数据和视图同步 不然会出现当页面为55,且最大值为100的时候,再输入一个5,页面会呈现100,但是实际值为555,会页面与值不同步
input.dispatchEvent(new Event('input'));
}
};
el.handlerChange= function (event){
let input = event.target;
let value = input.value;
let oldValue = input.value;
// 当输入框失去焦点或者回车的时候,如果不能转换成数字类型,则置为空 比如 - . -.
if(isNaN(Number(value))){
value=''
}
value=value.replace(/\.$/g, '') // 以小数点结尾将小数点置为空
value=value===''?'':Number(value)
// 判断是否需要更新,避免进入死循环
input.value = value;
if (oldValue.toString() !== value.toString()) {
// 手动触发 input 事件以确保数据和视图同步 不然会出现当页面为'',实际值为 -
input.dispatchEvent(new Event('input'));
}
}
el.addEventListener('input', el.handlerInput);
el.addEventListener('change', el.handlerChange);
},
unmounted(el) {
el.removeEventListener('input', el.handlerInput);
el.removeEventListener('change', el.handlerChange);
}
})
}
在main.js中注册
import limitNumberfrom '@/directive/limitNumber.js'
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
app.use(limitNumber)
使用
<template>
<div>
<el-input class="width-120" v-limitNumber="{ max: 100}" v-model="intNum" placeholder="正整数" />
<el-input class="width-120" v-limit-number="{ min: -100, max: 100 }" v-model="positiveNum" placeholder="数数" />
<el-input class="width-120" v-limit-number="{ min: -100, max: 100, decimal: 1 }" v-model="onePointNum" placeholder="一位小数" />
<el-input class="width-120" v-limit-number="{ min: -100, max: 100, decimal: 6 }" v-model="twoPointNum" placeholder="两位小数" />
</div>
</template>
<script setup>
import { onMounted,ref } from 'vue';
const intNum=ref('')
const positiveNum=ref('')
const onePointNum=ref('')
const twoPointNum=ref('')
onMounted(() => {
});
</script>
<style lang="less" scoped>
.width-120{
display: block;
width: 120px;
}
</style>