在vue2.0中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通DOM元素进行底层操作,除了默认的内置指令,比如v-model、v-show等等,但有时候需求并不限于这些,所以需要开发人员自定义指令。

此文就来实现一个只能输入指定位数数字的自定义指令

在src目录下新建directive文件夹

1.新建module文件夹,然后新建number-only.js

let findEle = (parent, type) => {
  return parent.tagName.toLowerCase() === type
    ? parent
    : parent.querySelector(type);
};

function filterNum(arg) {
  return arg > 0
    ? new RegExp(`^\\d+(?:\\.\\d{0,${arg}})?$`)
    : new RegExp(`^\\d+$`);
}

function reducerObj(object) {
    if (typeof object !== 'object') throw Error('param is expected object');
    let data = object;

    function split(keyStr) {
      return keyStr.split('.');
    }

    function hasOwn(result, key) {
      if (result.hasOwnProperty(key)) {
        return result[key]
      }
      throw Error(key + ' is not exist')
    }

    return {
      value: data,
      get(keyStr) {
        let keys = split(keyStr);
        return keys.reduce((result, key, idx, arr) => {
          return hasOwn(result, key);
        }, data)
      },
      set(keyStr, val) {
        let keys = split(keyStr);
        let d = null, preKey;
        let oldVal = keys.reduce((result, key, idx, arr) => {
          d = result;
          preKey = key;

          return hasOwn(result, key);
        }, data);

        d[preKey] = val;

        return {
          val: d[preKey],
          oldVal
        }
      }
    }
  },

export default {
  name: 'numberOnly',
  options: {
    bind: function (el, options, vnode) {
      let $inp = findEle(el, 'input');
      // 默认
      let filter = options.arg;

      let reg = filterNum(filterNum);

      //可以动态 设置 过滤位数
      Object.defineProperty($inp, 'filterReg', {
        get() {
          return reg;
        },
        set(val) {
          filter = val;
          reg = filterNum(val);
        },
        enumerable: true,
        configurable: true
      });

      el.$inp = $inp;

      // 读写生成器
      let reducer = reducerObj(vnode.context);
      $inp.handle = function () {
        let numberOnly = this.getAttribute('number-only');
        if (numberOnly > 0 && filter !== numberOnly) this.filterReg = numberOnly;
        if (this.value.length && !this.filterReg.test(this.value)) {
          $inp.value = reducer.get(options.expression);
        } else {
          reducer.set(options.expression, this.value);
        }
        return false;
      };

      $inp.addEventListener('input', $inp.handle);
    },
    // update(...ddd) {
    //   console.log(ddd);
    // },
    unbind: function (el) {
      el.$inp.removeEventListener('input', el.$inp.handle);
    }
  }
};

2.在module同级目录新建directives.js

import numberOnly from './module/numberonly'

const importDirective = Vue => {
  Vue.directive(NumberOnly.name, NumberOnly.options);
}

export default importDirective

3.main.js

import importDirective from './directive'
importDirective (Vue)

4.使用 

<input :value="value" v-number-only:0="value"/>表示只能输入整数
<input :value="value" v-number-only:2="value"/>表示可以最多可以输入两位小数
Logo

前往低代码交流专区

更多推荐