el-input中文输入法疯狂输入拼音后获取不到值

225 阅读1分钟

需求

最近有个需求,在input输入之后过滤不是数字的字符,这种需求是很常见的,于是就简单写了一个自定义指令,代码如下:

<el-input v-model="form.hsCode"  v-checkInput.numeric />
import type { App, Directive, DirectiveBinding } from 'vue'
const checkInput: Directive = (el: HTMLElement, binding: DirectiveBinding) => {
  let inp: HTMLInputElement
  if (el.tagName.toLowerCase() === 'input') {
    inp = el as HTMLInputElement
  }
  else {
    inp = (el.querySelector('input') || el.querySelector('textarea')) as HTMLInputElement
  }
  function numeric(value: string) {
    return value.replace(/\D/g, '')
  }
  inp.addEventListener('input', (e) => {
    if (binding.modifiers.numeric)
      return (inp.value = numeric(inp.value.toString()))
  })
}
export default (app: App) => app.directive('checkInput', checkInput)

以上代码自测的时候并没有发现有什么问题,产品测试时在中文输入法下疯狂输入拼音后发现问题,输入结束后el-form的校验始终获取不到输入的值,查询后才知道当我们输入中文后,由于拼音也会触发input事件,以至于输入框一直在触发input事件,造成了卡顿,无法获取到值。

解决方案

方案一:使用compositionstartcompositionend解决这个问题

  • compositionstart:开始新的输入合成时会触发compositionstart事件
  • compositionend:当文本段落的组成完成或者取消时会触发componsitionend事件 实现代码如下
import type { App, Directive, DirectiveBinding } from 'vue'
const checkInput: Directive = (el: HTMLElement, binding: DirectiveBinding, vnode: any) => {
  let inp: HTMLInputElement
  if (el.tagName.toLowerCase() === 'input') {
    inp = el as HTMLInputElement
  }
  else {
    inp = (el.querySelector('input') || el.querySelector('textarea')) as HTMLInputElement
  }

  function numeric(value: string) {
    return value.replace(/\D/g, '')
  }
  inp.addEventListener('compositionstart', () => {
    vnode.inputLocking = true
  })
  inp.addEventListener('compositionend', () => {
    if (!vnode.inputLocking)
      return
    vnode.inputLocking = false
    inp.dispatchEvent(new Event('input'))
  })
  inp.addEventListener('input', (e) => {
    e.preventDefault()
    if (vnode.inputLocking) {
      return
    }
    if (binding.modifiers.numeric)
      return (inp.value = numeric(inp.value.toString()))
  })
}
export default (app: App) => app.directive('checkInput', checkInput)

方案二:不使用自定义指定,直接在使用input事件,将处理后的值赋值给form对象相应的属性

<el-input 
    v-model="formData.hsCode" 
    @input="form.hsCode = form.hsCode.replace(/\D/g, '')"
/>