真香系列:vue input 数字指令(全能系列)

220 阅读1分钟

功能

  • 只能输入数字类型
  • 限制输入最小最大值(v-input-number.pi={min:0 , max:200, cb})
  • 限制小数位(v-input-number.float="{f:2 ,cb})
  • 不限制小数位(v-input-number.float="{cb})
  • 限制输入整数(v-input-number={cb})
    • 备注cb函数必须,cb传出处理好的值,再修改data上面的属性

注册全局指令

// main.js 里面
import inputNumber from './directive/inputNumber';
Vue.use(inputNumber);

用法

    // v-input-number={cb:(v)=>{ // 修改vmodel的值}}  整数
    // v-input-number.pi={min:0 , max:200, cb:(v)=>{ // 修改vmodel的值}}  正整数 最小0 最大为200
    // v-input-number.float="{cb: (v)=>{ // 修改vmodel的值}}" 浮点数
    // v-input-number.float="{f:2 ,cb:(v)=>{ // 修改vmodel的值}}" 保留2位浮点数
  <el-input v-input-number.float="{f:2 ,cb:(v)=>{ number = v }}" size="mini" v-model="number"></el-input>

灵感来源

源码

export const superTypeOf = (obj) => {
    return Object.prototype.toString.call(obj).slice(8, -1)
}

export function checkIsNull(v) {
    if (superTypeOf(v) == 'Array') {
        return (v.length === 0)
    } else if (superTypeOf(v) == 'Object') {
        return (Object.keys(v).length === 0)
    }
    return v === '' || v === null || v === undefined
}

function onInput(el, ele, binding) {
  function handle() {
    let bv = binding.value
    let cFloat = bv ? (checkIsNull(bv.f) ? '' : bv.f ) : ''
    let val = ele.value
    let max = bv.max
    let min = bv.min
    // 清除"数字"和"."以及"-"以外的字符
     val = val.replace(/[^\-\d.]/g, '');
     // 只保留第一个'-'号
     val = val.replace(/\.{2,}/g, '.').replace(/-{2,}/g, '-')
     // 出现-3-4-5 保留首个- 即 -345
     if (/(-)/g.test(val)) {
       val = val.replace(/-/g, '');
       val = '-' + val;
     }
     // 将 '-.' 替换成 '-0.'
     val = val.replace(/^\./g, '0.').replace(/^-\./, '-0.')
     // 00 | -00 开头 转成 0 | -0
     val =  val.replace(/^(\-?)(00)/g, '$10').replace(/^0([\w])(?!\.)/, '$1')

    // modifiers为修饰符对象,传入了float,则其float属性为true
    if (binding.modifiers) {
      let {float, pi} = binding.modifiers
      if (typeof cFloat !== 'undefined' && float) {
        // 期望保留的最大小数位数
        let pointKeep = 0;
        if (typeof cFloat === 'string' ||
          typeof cFloat === 'number') {
          pointKeep = Number.parseInt(cFloat, 10);
        }
        if (!isNaN(pointKeep)) {
          if (!Number.isInteger(pointKeep) || 
          pointKeep < 0) {
            pointKeep = 0;
          }
        }
        // 增加'-'号的支持
        const str = '^(\\-)*(\\d+)\\.(\\d{' + pointKeep + '}).*$';
        const reg = new RegExp(str);
        if (pointKeep === 0) {
        // 不需要小数点
          val = val.replace(reg, '$1$2');
        } else {
        // 通过正则保留小数点后指定的位数
          val = val.replace(reg, '$1$2.$3');
        }
      }else if(pi){
        val = val.replace(/\-|\./g, '').replace(/^0(?=[\d+])/g,'')
      }
      if (!checkIsNull(min)) {
        if (val < min) {
          val = min
        }
      }
      if (!checkIsNull(max)) {
          if (val > max) {
            val = max
          }
      }
    } else {
      val = ele.value.replace(/[^\d]/g, '');
    }
    ele.value = val;
    bv&&bv.cb(val)
  }
  return handle;
}

const inputNumber = {
  bind: function(el, binding) {
      const ele = el.tagName === 'INPUT' ? el : el.querySelector('input');
      ele.__func__ = onInput(el, ele, binding)
      // 指令绑定到元素时并绑定事件
      ele.addEventListener('input', ele.__func__, false);
  },
  unbind:function(el, binding) {
    const ele = el.tagName === 'INPUT' ? el : el.querySelector('input');
      // 指令与元素解绑时移除绑定的函数
    ele.removeEventListener('input', ele.__func__, false);
  }
};

const install = function(Vue) {
  Vue.directive('input-number', inputNumber);
};

if (window.Vue) {
  window.inputNumber = inputNumber;
  Vue.use(install); // eslint-disable-line
}

inputNumber.install = install;
export default inputNumber;