v-number 指令主要为了统一解决数字输入的限制问题 1.失去焦点输入框中的值进行千分位处理,绑定的值不进行千分位处理 2.小数位的限制输入 3.最值限制
// 文件 directive-tool.js
/**
* 千分位处理函数
* @param {*} num 传入的值
* @param {*} dot 千分位符合 默认使用逗号
* @returns
*/
export function formatThousand(num, dot = ',') {
let str = '';
if (typeof num === 'number') {
str = num.toString();
} else if (typeof num === 'string') {
if (num === '') return '';
if (Number.isNaN(Number(num))) {
console.error(`${num} is NaN`);
return '';
}
str = num;
} else {
console.error(`${num} is NaN`);
return '';
}
const strs = str.split('.');
let pre = '';
const midx = strs[0][0] !== '-' ? 3 : 4;
let idx = strs[0].length;
while (idx > midx) {
const idx_pre = idx - 3;
pre = pre === '' ? strs[0].slice(idx_pre, idx) : `${strs[0].slice(idx_pre, idx)}${dot}${pre}`;
idx = idx_pre;
}
pre = pre === '' ? strs[0] : `${strs[0].slice(0, idx)}${dot}${pre}`;
return strs.length === 1 ? pre : `${pre}.${strs[1]}`;
}
/**
* 清除千分位处理函数
* @param {*} str 传入的值
* @param {*} dot 千分位符号
* @returns
*/
export function formatClearThousand(str, dot = ',') {
if (typeof str !== 'string') {
console.error(`${str} is not string`);
return str;
}
const strs = str.split(dot);
return strs.join('');
}
// 文件 demo.vue
<template>
<div>
<el-input v-number="{ max: 20110, min: -100, preserve: 4, thousand: true }" v-model="val" />
</div>
</template>
<script>
import { formatThousand, formatClearThousand } from './directive-tool';
/**
* 指令 v-number 用于控制输入框输入数字限制
* max 最大值限制
* min 最小值
* preserve 保留的小数点位数
* thousand 是否在失去焦点的时候做千分位处理
*/
export default {
directives: {
number: {
bind(el, binding, vnode) {
const input = el.getElementsByTagName('input')[0];
let preserve = Number(binding.value.preserve);
if (Number.isNaN(preserve) && binding.value.preserve !== undefined) {
console.error(`v-number:{ preserve : ${binding.value.preserve} } is NaN`);
}
// 最值限制
const limitVal = (val) => {
let nv = val;
if (binding.value.max !== undefined) {
// 最大值限制
const max = Number(binding.value.max);
if (Number.isNaN(max)) console.error(`v-number:{ max : ${binding.value.max} } is NaN`);
else nv = nv > max ? max : nv;
}
if (binding.value.min !== undefined) {
// 最小值限制
const min = Number(binding.value.min);
if (Number.isNaN(binding.value.min)) console.error(`v-number:{ min : ${binding.value.min} } is NaN`);
else nv = nv < min ? min : nv;
}
return nv;
};
preserve = Number.isNaN(preserve) ? 2 : preserve;
input.oninput = (event) => {
if (input.value === '') return;
const vals = [];
const idx = input.value.indexOf('.');
if (idx === -1) {
vals.push(input.value);
} else {
const pre = input.value.slice(0, idx);
if (pre !== '') vals.push(input.value.slice(0, idx));
vals.push(input.value.slice(idx + 1, input.value.length));
}
vals.forEach((val, index) => {
if (index === 0) {
if (val[0] === '-') {
vals[index] = `-${val.slice(1, val.length).replace(/[^\d]/g, '')}`;
} else {
vals[index] = val.replace(/[^\d]/g, '');
}
} else {
vals[index] = val.replace(/[^\d]/g, '');
}
});
input.value = limitVal(vals.join('.'));
vnode.componentInstance.$emit('input', input.value);
};
input.onfocus = (event) => {
input.value = formatClearThousand(input.value, binding.value?.dot || ',');
};
input.onblur = (event) => {
if (input.value === '') return;
const vals = [];
const idx = input.value.indexOf('.');
if (idx === -1) {
vals.push(input.value);
vals.push('');
} else {
const pre = input.value.slice(0, idx);
if (pre !== '') vals.push(input.value.slice(0, idx));
vals.push(input.value.slice(idx + 1, input.value.length));
}
const c = [];
const cs = vals[1];
for (let i = 0; i < preserve; i += 1) {
c[i] = i < cs.length ? cs[i] : '0';
}
if (preserve === 0) {
input.value = String(vals[0]);
} else {
vals[1] = c.join('');
input.value = vals.join('.');
}
input.value = limitVal(input.value);
vnode.componentInstance.$emit('input', input.value);
if (binding.value.thousand) {
setTimeout(() => {
input.value = formatThousand(input.value, binding.value?.dot || ',');
}, 500);
}
};
},
inserted(el, binding, vnode) {
const input = el.getElementsByTagName('input')[0];
if (binding.value.thousand) input.value = formatThousand(input.value, binding.value?.dot || ',');
},
},
},
data() {
return { val: '' };
},
};
</script>