前言
前端项目中,输入框是常见的,数字输入框更是常见,我们也许用惯了UI框架或是第三方提供的数字输入框,其实我们内心也想拥有自己的一个数字输入框指令,进可以攻(
灵活使用
),退可以守(灵活扩展
),一切尽在掌握之中,不尽于被动。
需求
最近用到了 数字输入框,需求需要满足:
- 设置输入的小数位数
- 设置是否支持输入符号
- 支持最值(最大值、最小值)
- 设置边界超出处理 (1、超出是否替换成最值 2、超出最值无法进一步输入)
首先来看下配置属性有哪些:
- max – 输入数字最大值
- min – 输入数字最小值
- digit – 设置小数位数
- negative 是否支持输入符号
- isReplace – 超出最值 是采用替换成对应最值
使用
我们再来看下我们想如何使用:
以下需求为
允许输入符号,允许输入最大值为 99999999,允许输入最小值为 -99999999,小数保留位数 2
源码及示例
Vue2 数字输入框指令
默认状态
- 输入的小数位数digit:2
- 输入数字最大值max:无限制
- 输入数字最小值min:无限制
- 是否允许输入负号negative:不允许
- 超出最值 是否允许采用替换成对应最值isReplace:不允许
自定义状态1
- 输入的小数位数digit:0
- 输入数字最大值max:999
- 输入数字最小值min:-999
- 是否允许输入负号negative:允许
- 超出最值 是否允许采用替换成对应最值isReplace:允许
自定义状态2
- 输入的小数位数digit:0
- 输入数字最大值max:999
- 输入数字最小值min:0
- 是否允许输入负号negative:不允许
- 超出最值 是否允许采用替换成对应最值isReplace:不允许
/**
*
数字输入框,需求满足:
设置输入的小数位数
设置是否支持输入fushu负号
支持最值(最大值、最小值)
设置边界超出处理 (1、超出是否替换成最值 2、超出最值无法进一步输入)
配置属性:
max - 输入数字最大值
min - 输入数字最小值
digit - 设置小数位数
negative 是否支持输入符号
isReplace - 超出最值 是采用替换成对应最值
*
*
*/
new Vue({
el:'#app',
data:{
},
directives:{
number: {
bind (el, binding) {
// input 输入框 元素 兼容
if (el.tagName !== 'INPUT') el = el.querySelector('input')
服务器托管网 el.old = '' // 记录旧值
el.handler = function () {
if(el.lock)return
const { max, digit, min, negative, isReplace } = binding.value || {}
// 小数位数正则
const digitReg = new RegExp(`^\d*(服务器托管网\.?\d{0,${digit === undefined ? 2 : digit}})`, 'g')
// 最新值是否是负数
const isNegative = el.value.includes('-')
// 最新的输入框内的值
const val = el.value
// 其它非法值进行处理
let newValue = el.value.replace(/[^d.]/, '')
.replace(/,/g, '')
.replace(/^0+(d)/, '$1') // 第一位0开头,0后面为数字,则过滤掉,取后面的数字
.replace(/^./, '0.') // 如果输入的第一位为小数点,则替换成 0. 实现自动补全
.match(digitReg)[0] || '' // 最终匹配得到结果 以数字开头,只有一个小数点,而且小数点后面只能有0到2位小数
// 负数 并且 允许输入符号
if (isNegative && negative) {
if (val.match(/-/g)?.length === 2) newValue = val.split('-').join('')
newValue = '-' + newValue
}
if (newValue.slice(-1) === '.' && digit === 0) {
newValue = Number(newValue)
}
// 输入值超出最值 , isReplace 为 true 就 替换,否则就还原上次输入的值
if (max !== undefined && newValue > max) {
newValue = isReplace ? max : String(newValue).slice(0, -1)
} else if (min !== undefined && newValue < min) {
newValue = isReplace ? min : String(newValue).slice(0, -1)
} else { // 输入值未超出最值
el.old = newValue
}
// 判断是否需要更新,避免进入死循环
if (newValue !== el.value) {
el.value = newValue
el.dispatchEvent(new Event('input')) // 通知v-model更新
}
}
el.blurHander = function (e) {
const { digit } = binding.value || {}
const digitReg = new RegExp(`^\d*(\.?\d{0,${digit === undefined ? 2 : digit}})`, 'g')
if (el.value === '-') {
el.value = ''
el.dispatchEvent(new Event('input')) // 通知v-model更新
return
}
let newValue = el.value.replace(/[^d.]/, '')
.replace(/^0+(d)/, '$1') // 第一位0开头,0后面为数字,则过滤掉,取后面的数字
.replace(/^./, '0.') // 如果输入的第一位为小数点,则替换成 0. 实现自动补全
.match(digitReg)[0] || '' // 最终匹配得到结果 以数字开头,只有一个小数点,而且小数点后面只能有0到2位小数
if (newValue.slice(-1) === '.' && digit !== 0 && digit !== undefined) {
newValue = Number(newValue)
el.value = newValue
el.dispatchEvent(new Event('input')) // 通知v-model更新
}
}
el.compositionstart = function(e){
el.lock = true
e.preventDefault();
e.stopPropagation();
}
el.compositionend = function(e){
el.lock = false
el.value = parseFloat(el.value)
el.dispatchEvent(new Event('input'))
e.preventDefault();
e.stopPropagation();
}
el.addEventListener('input', el.handler)
el.addEventListener('blur', el.blurHander)
el.addEventListener('compositionstart', el.compositionstart)
el.addEventListener('compositionend', el.compositionend)
},
unbind (el) {
el.removeEventListener('input', el.handler)
el.removeEventListener('blur', el.blurHander)
el.removeEventListener('compositionstart', el.compositionstart)
el.removeEventListener('compositionend', el.compositionend)
}
}
}
})
指令的大致实现过程就监听输入,根据输入值进行各种场景的处理,
compositionstart
和compositionend
来处理 输入中文的特殊场景,经过自测和项目中的使用,基本满足需求,如果不满足你的需求,可以复制下来进行扩展,实现思路 可以用于React、Vue3等其他,万变不离其宗。
学习资料:点此下载
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net