vue自定义指令,校验输入框输入指定位数字

1,024 阅读1分钟

/*
* 自定义指令:校验输入框 (vue3)
* 输入类型为数字,可指定最大最小值,可保留指定位小数
* 同时可支持原生标签,也可支持类似 element-ui, vant-ui等UI组件
* 使用方法:
*   v-input-number="{ min: 0, max: 1000, precision: 2 }"
*   默认不传参 min: 最小值   max: 最大值  precision: 保留小数位
*   <input v-model="form.price" type="number" v-input-number>
*   <van-field v-model="form.price" placeholder="请输入" type="number" v-input-number="{ min: 0, max: 1000 }"></van-field>
*   <el-input v-model="form.price" placeholder="请输入" type="number" v-input-number="{ min: 0, max: 1000, precision: 2 }"></el-input>
* */
export default {
    install(app) {
        app.directive('input-number', {
            mounted(el, binding, vNode) {
                // 获取 input 输入框
                const input = (el) => el instanceof HTMLInputElement ? el : el.querySelector('input')

                const vm = input(el)

                if (!vm) return;

                let content

                // 设置输入框的值,触发input事件,改变v-model绑定的值
                const setVal = val => {
                    vm.value = val
                    vm.dispatchEvent(new Event('input'))
                }

                // 按键按下=>只允许输入 数字/小数点/减号
                el.addEventListener('keypress', event => {
                    const e = event || window.event
                    const inputKey = String.fromCharCode(typeof e.charCode === 'number' ? e.charCode : e.keyCode)
                    const re = /\d|.|-/
                    content = e.target.value

                    // 定义方法,阻止输入
                    function preventInput() {
                        if (e.preventDefault) {
                            e.preventDefault()
                        } else {
                            e.returnValue = false
                        }
                    }
                    if (!re.test(inputKey) && !e.ctrlKey) {
                        preventInput()
                    } else if (content.indexOf('.') > 0 && inputKey === '.') {
                        // 已有小数点,再次输入小数点
                        preventInput()
                    }
                })

                // // 按键弹起=>并限制最大最小
                el.addEventListener('keyup', event => {
                    const e = event || window.event
                    content = parseFloat(e.target.value)
                    if (!content) content = 0

                    let arg_max = binding?.value?.max || undefined
                    let arg_min = binding?.value?.min || undefined

                    if (arg_max !== undefined && content > arg_max) {
                        setVal(arg_max)
                        content = arg_max
                    }
                    if (arg_min !== undefined && content < arg_min) {
                        setVal(arg_min)
                        content = arg_min
                    }
                })

                // 失去焦点=>保留指定位小数
                el.addEventListener('focusout', event => { // 此处会在 el-input 的 @change 后执行
                    content = parseFloat(vm.value)

                    if (!content) content = 0

                    // 保留 多少位 小数, 如果没值则默认保留整数
                    let arg_precision = binding.value?.precision ? parseInt(binding.value.precision) : 0

                    // 如果输入数小于保留位数,则值不变
                    vm.value = content.toString().split('.')[1]?.length < arg_precision ? content : content.toFixed(arg_precision)

                    setVal(vm.value)
                })
            }
        })
    }
}