职场偷懒之vue自定义指令处理数字保留的位数

173 阅读3分钟

在用vue指令前我这样子的

    <el-input
      type="text"
       v-model="editOrderForm.phoneNumber"
      oninput="value=value.replace(/[^\d]/g,'')"
    ></el-input>

这是限制只输入数字,而且这个好像还有个bug,切换中文输入法后输入会导致v-model失效 或者是写一个方法,在方法里tofix一下再赋值,但是一个页面要是有多个输入框就显得繁琐,有木有同感~~。

vue自定义指令

vue除了我们平常用开的v-for,v-show,v-model等指令还支持我们自定义指令实现业务需求。 下面这段是我写好的vue自定义指令就是用来处理数字保留的位数的

export default (Vue) => {
  Vue.directive("numberInt", {
   update: function (el, binding, vnode) {
     if (!binding.value) {
         return
      }
    let arg = binding.arg
    let re = binding.arg == 0 ? "\\d+(d{0," + arg + "})?" : "\\d+(\\.\\d{0," + arg + "})?"
    var reg = eval("/" + re + "/")
    try {
      let a = (binding.value.match(reg) || [''])[0]
      vnode.data.model.callback(a)
    }
    catch{
        return
    }
   }
 })
}

钩子函数

指令定义函数提供了几个钩子函数(可选):

  • bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
  • inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)
  • update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新(所以这里我采用update,因为输入框input输入过程中内容是一直在动态变化的)。
  • componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。
  • unbind: 只调用一次, 指令与元素解绑时调用。
  • 钩子函数的参数

     1、el: 指令所绑定的元素,可以用来直接操作 DOM 。
     2、binding: 一个对象,包含以下属性:
         name: 指令名,不包括 v- 前缀 例如 v-numberInt name就是numberInt 。
         value: 指令的绑定值, 例如 v-numberInt:0="registerVipCardForm.smobile", value 
                的值是你当前绑定的这个registerVipCardForm.smobile的值。
         arg: 传给指令的参数。例如v-numberInt:0, arg 的值是 "0"。
     3、vnode: Vue 编译生成的虚拟节点。
    

实现(需求)

需求:需要只能输入数字并且可以输入参数自定义保留多少位数字

首先还是想到用正则表达是过滤掉用户输入的乱七八糟的中文或者符号,然后需要从binding对象中获取 arg参数:如 v-numberInt:0, arg 的值是 "0"。这样意思就是不保留小数只能输入整数。拿到这个参数之后,我们就需要把它填入到我们的正则表达式。

    let arg = binding.arg
    let re = binding.arg == 0 ? "\\d+(d{0," + arg + "})?" : "\\d+(\\.\\d{0," + arg + "})?"
    var reg = eval("/" + re + "/")

这里用三元表达式来控制我们要不要小数点,当arg为0的时候我们就不需要小数点了也把它过滤掉。 这里为什么要用 ' \\ ' 呢 因为要输出 \ 就要用到转义符 ,然后用eval运算才能得到我们想要的正则表达式 / \d+(\.\d{0," + arg + "})?"/,最后

    try {
      let a = (binding.value.match(reg) || [''])[0]
      vnode.data.model.callback(a)
    }
    catch{
        return
    }

a就是我们最后要的值了,然后用 vnode.data.model.callback(a)更新到我们的视图。

pass:

如果你想要控制整数的位数,可以多传一个参数。然后正则表达式改成 假设传过来的整数位是a,指令那边传个对象过来v-numberInt:{a:1,b:2} "\d{1," + a + "}(\.\d{0," + arg + "})?"