UNPKG

v-number-only-directive

Version:

用于vue2+element-ui项目,限制其el-input输入内容只能为数字

133 lines (109 loc) 4.39 kB
function getRegex(options) { if (options.decimal && options.negative) return /^-?\d*(\.\d*)?$/ if (options.decimal) return /^\d*(\.\d*)?$/ if (options.negative) return /^-?\d*$/ return /^\d*$/ } function formatValue(value, options, { strict = false } = {}) { let allowedChars = '0-9' if (options.decimal) allowedChars += '\\.' if (options.negative) allowedChars += '\\-' const cleanReg = new RegExp(`[^${allowedChars}]`, 'g') let result = value.replace(cleanReg, '') // 保留单个负号 if (options.negative) { result = result[0] === '-' ? '-' + result.slice(1).replace(/-/g, '') : result.replace(/-/g, '') } // 只保留第一个小数点 const parts = result.split('.') if (parts.length > 2) { result = parts.shift() + '.' + parts.join('').replace(/\./g, '') } const reParts = result.split('.') // 去除前导0(仅整数时) if (!options.decimal || reParts.length === 1) { result = result.replace(/^(-?)0+(\d)/, '$1$2') } const endsWithDot = result.endsWith('.') // "-"开头 const isIntermediate = !strict && ( result === '-' || result === '.' || result === '-.' || (options.decimal && /^-?\d+\.$/.test(result)) ) if (isIntermediate) return result if (!strict && /^-?$/.test(result)) return result // 小数位数限制 if (options.maxDecimalPlaces !== undefined && options.decimal && reParts.length === 2) { reParts[1] = reParts[1].slice(0, options.maxDecimalPlaces) result = reParts.join('.') } let num = parseFloat(result) if (!isNaN(num)) { if (options.min !== undefined) num = Math.max(num, options.min) if (options.max !== undefined) num = Math.min(num, options.max) result = options.decimal ? String(num) : String(Math.floor(num)) if (!strict && endsWithDot && !result.includes('.')) { result += '.' } } else { result = options.allowEmpty ? '' : '0' } return result } const numberOnly = { bind(el, binding) { const input = el.tagName.toLowerCase() === 'input' ? el : el.querySelector('input') if (!input) return const options = Object.assign({ allowEmpty: true }, binding.value || {}) let isComposing = false if (!options.allowEmpty && (input.value === '' || input.value == null)) { input.value = '0' input.dispatchEvent(new Event('input')) } const handler = () => { if (isComposing) return const val = input.value if (options.allowEmpty && val === '') return const formatted = formatValue(val, options, { strict: false }) if (formatted !== input.value) { input.value = formatted input.dispatchEvent(new Event('input')) } } const blurHandler = () => { const val = input.value if (options.allowEmpty && val === '') return const formatted = formatValue(val, options, { strict: true }) if (formatted !== input.value) { input.value = formatted input.dispatchEvent(new Event('input')) } } input.__numberOnlyHandler__ = handler input.__numberOnlyBlurHandler__ = blurHandler input.addEventListener('input', handler) input.addEventListener('blur', blurHandler) input.addEventListener('compositionstart', () => isComposing = true) input.addEventListener('compositionend', () => { isComposing = false handler() }) }, unbind(el) { const input = el.tagName.toLowerCase() === 'input' ? el : el.querySelector('input') if (input) { input.removeEventListener('input', input.__numberOnlyHandler__) input.removeEventListener('blur', input.__numberOnlyBlurHandler__) delete input.__numberOnlyHandler__ delete input.__numberOnlyBlurHandler__ } } } // 插件形式 export default { install(Vue) { Vue.directive('number-only', numberOnly) } } // 可按需导入 export const NumberOnlyDirective = numberOnly