1

一直都想搞一个能够统一处理input框限制的小工具,最近新项目有需要,就借鉴了一下大佬们的文档博客,自己记录一下。
废话不多说,直接上代码:

//index.vue

<template>
// 纯数字
<el-input v-input-filter:num="ruleForm.warningNum" v-model="ruleForm.warningNum" placeholder="请输入数字"></el-input>
// 纯数字 + 小数点
<el-input v-input-filter:num.point="ruleForm.warningNum" v-model="ruleForm.warningNum" placeholder="请输入数字"></el-input>
</template>

// directive.js

import Vue from 'vue'

// 限制只能输入数字 小数点的限制由修饰符控制
const onlyNum = (el, bindings, vnode) => {
  let regExp = /[^\d]/g
  if (bindings.modifiers['point']) {
    // 修饰符 ‘point’
    regExp = /[^\d\.]/g
  }
  fnSaveCursorPos(el, bindings, vnode, regExp)
}

// 限制只能输入字母(包含大小写字母)
const onlyLetter = (el, bindings, vnode) => {
  let regExp = /[^a-z|A-Z]/g
  if (bindings.modifiers['point']) {
    // 修饰符 ‘point’
    regExp = /[^a-z|A-Z|.]/g
  }
  fnSaveCursorPos(el, bindings, vnode, regExp)
}

// 限制只能输入字母和数字(包含大小写字母)
const onlyLetterNum = (el, bindings, vnode) => {
  let regExp = /[^a-z|A-Z\d]/g
  fnSaveCursorPos(el, bindings, vnode, regExp)
}

Vue.directive('input-filter', {
  update(el, bindings, vnode) {
    switch (bindings.arg) {
      case 'num':
        onlyNum(el, bindings, vnode)
        break
      case 'letter':
        onlyLetter(el, bindings, vnode)
        break
      case 'num-letter':
        onlyLetterNum(el, bindings, vnode)
        break
      default:
        console.log('此方法暂无增加')
        break
    }
  }
})

// 处理光标位置,避免重新赋值之后光标出现在末尾
function fnSaveCursorPos(el, bindings, vnode, regExp) {
  bindings.value = bindings.value + ''
  let inputEl = el
  if (el.tagName !== 'INPUT') {
    inputEl = el.querySelector('input')
  }
  if (!inputEl) {
    console.log('没有input')
    return
  }
  const inputElCursorPos = inputEl.selectionStart // 输入框输入之后的光标位置
  const regExpStringLength = (bindings.value.match(regExp) || []).length // 被清除的字符长度
  fnSetVal(vnode.context, bindings.expression, bindings.value.replace(regExp, ''))
  inputEl.setSelectionRange(inputElCursorPos - regExpStringLength, inputElCursorPos - regExpStringLength)
  const timer = setTimeout(() => {
    // console.log('inputEl', inputElCursorPos - regExpStringLength)
    clearTimeout(timer)
    inputEl.setSelectionRange(inputElCursorPos - regExpStringLength, inputElCursorPos - regExpStringLength)
  })
}

// 赋值处理, 例如:obj.key.key
function fnSetVal(data, fields, setVal) {
  if (Object.prototype.toString.call(data) === '[object Object]' && Object.prototype.toString.call(fields) === '[object String]') {
    const keys = fields.split('.')
    let value = data
    while (keys.length && value !== undefined) {
      if (keys.length === 1) {
        value[keys[0]] = setVal
        return
      }
      value = value[keys[0]]
      keys.shift()
    }
  }
}

利用自定义指令中‘更新’的生命周期来对绑定的值进行处理,但是这个会有两次的更新过程,第一次是原始值触发更新,第二次是处理限制之后触发的更新;感觉这里有点不太完美。
文章中如果有什么问题,欢迎指出~~~ 感谢!!!


Yang
17 声望0 粉丝