JavaScript中的composition event

最近在阅读Element-UI的input组件源码时,发现其使用了composition事件:


印象里红皮书好像有提到过,但已经记不清有什么作用了,趁此机会学习下。

composition event,即复合事件,用于处理IME的输入序列。
IME(Input Method Editor,输入法编辑器)可以让用户输入在物理键盘上找不到的字符。
其实就是我们用中文输入法时,出现的显示中文的框:


image.png

composition event包括三个事件:

  • compositonstart: 在IME的文本复合系统打开时触发,表示要开始输入例如(输入法出现的那一刻)
  • compositionupdate: 在向输入字段中插入新字符时触发(使用输入法输入的过程中)
  • compositionend: 在IME的文本复合系统关闭时触发,表示返回正常键盘输入状态(选中文字,输入法消失的那一刻)

那Element-UI为什么要使用composition event呢?
这其实跟composition event的作用有关,我们来看下compotion event与input event的触发顺序:


image.png

可以看到,首先输入法出现,触发了compositonstart事件,然后分别输入'w'和'o',先是触发compositionupdate事件,再是触发input事件。当然,如果选择了中文,会触发compositionend事件。
这里的重点是,在拼音还未转化成中文的时候,同时有两个输入框存在:

  • 页面上的input输入框
  • 输入法的输入框

两者分别会触发input和compositionupdate事件。这样问题就出现了,用过Element-UI或者类似UI库的同学都知道,input组件多数情况下都是配合着form组件使用的,既然是表单,那也离不开表单验证了。那么问题就在于,如果是通过input事件来触发验证的,输入的是字符,那倒没什么问题。可要是输入的是中文(或者其它需要组合拼出来的语言),比如,要输入'我',在拼音还没转换之前,网页输入框中的内容时'wo',也会触发验证,这并不是我们想要的!

因此,我们可以使用复合事件,通过一个变量来判断是否是在composition event中,是,就不去触发input事件。
当然,Element-UI也是这么做:

handleComposition(event) {
  if (event.type === 'compositionend') {
    this.isOnComposition = false;
    this.currentValue = this.valueBeforeComposition;
    this.valueBeforeComposition = null;
    this.handleInput(event);
  } else {
    const text = event.target.value;
    const lastCharacter = text[text.length - 1] || '';
    this.isOnComposition = !isKorean(lastCharacter);
    if (this.isOnComposition && event.type === 'compositionstart') {
      this.valueBeforeComposition = text;
    }
  }
}

该方法是composition event的统一处理方法,this.isOnComposition用来判是否开启了输入法,在compositionend事件触发时,将this.isOnCompostion = false; 表明输入法已关闭,再去执行this.handleInput,即input事件的处理方法。

handleInput(event) {
  const value = event.target.value;
  this.setCurrentValue(value);
  if (this.isOnComposition) return;
  this.$emit('input', value);
}

在handleInput方法中,可以看到,若this.isOnComposition为true,是不会执行this.$('input', value);的,即不会向父组件派发input事件,如果父组件是form组件,也就不会去触发表单验证了。

你可能感兴趣的:(JavaScript中的composition event)