前言
前端项目中,输入框是常见的,数字输入框更是常见,我们也许用惯了UI框架或是第三方提供的数字输入框,其实我们内心也想拥有自己的一个数字输入框指令,进可以攻(
灵活使用
),退可以守(灵活扩展
),一切尽在掌握之中,不尽于被动。
需求
最近用到了 数字输入框,需求需要满足:
- 设置输入的小数位数
- 设置是否支持输入符号
- 支持最值(最大值、最小值)
- 设置边界超出处理 (1、超出是否替换成最值 2、超出最值无法进一步输入)
首先来看下配置属性有哪些:
- max - 输入数字最大值
- min - 输入数字最小值
- digit - 设置小数位数
- negative 是否支持输入符号
- isReplace - 超出最值 是采用替换成对应最值
使用
我们再来看下我们想如何使用:
以下需求为
允许输入符号,允许输入最大值为 99999999,允许输入最小值为 -99999999,小数保留位数 2
<template>
<div class="hello">
<input type="text" v-number="{ negative: true, max: 99999999, min: -99999999 , digit:2 }">
</div>
</template>
源码及示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue2 数字输入框指令</title>
</head>
<body>
<div id="app">
<div class="item">
<div class="desc">
默认状态
<ul>
<li>输入的小数位数digit:2</li>
<li>输入数字最大值max:无限制</li>
<li>输入数字最小值min:无限制</li>
<li>是否允许输入负号negative:不允许</li>
<li>超出最值 是否允许采用替换成对应最值isReplace:不允许</li>
</ul>
</div>
<div class="input-wrap"><input type="text" v-number></div>
</div>
<div class="item">
<div class="desc">
自定义状态1
<ul>
<li>输入的小数位数digit:0</li>
<li>输入数字最大值max:999</li>
<li>输入数字最小值min:-999</li>
<li>是否允许输入负号negative:允许</li>
<li>超出最值 是否允许采用替换成对应最值isReplace:允许</li>
</ul>
</div>
<div class="input-wrap"><input type="text" v-number="{digit:0,min:-999,max:999,negative:true,isReplace:true}"></div>
</div>
<div class="item">
<div class="desc">
自定义状态2
<ul>
<li>输入的小数位数digit:0</li>
<li>输入数字最大值max:999</li>
<li>输入数字最小值min:0</li>
<li>是否允许输入负号negative:不允许</li>
<li>超出最值 是否允许采用替换成对应最值isReplace:不允许</li>
</ul>
</div>
<div class="input-wrap"><input type="text" v-number="{digit:0,min:-999,max:999,negative:false,isReplace:false}"></div>
</div>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
/**
*
数字输入框,需求满足:
设置输入的小数位数
设置是否支持输入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)
}
}
}
})
</script>
</html>
指令的大致实现过程就监听输入,根据输入值进行各种场景的处理,
compositionstart
和compositionend
来处理 输入中文的特殊场景,经过自测和项目中的使用,基本满足需求,如果不满足你的需求,可以复制下来进行扩展,实现思路 可以用于React、Vue3等其他,万变不离其宗。
学习资料:点此下载
标签:el,digit,value,输入框,最值,Vue2.0,新手,newValue,输入 From: https://blog.51cto.com/u_15723831/9431082