compositionEvent组合事件,来填补React input输入框onchange事件的坑

6,644 阅读3分钟
...
<input ref="inputTest" type="text" placeholder="测试" value={this.state.val}
onChange={this.inputValue}/>
...
inputValue(e){
    this.setState({
        val:e.target.value
    })
}

以上这段代码,相信大家再熟悉不过了,react controlled组件的最简单的栗子,controlled input组件。首先我们来说一说React的事件,包括上面我们使用的onChange事件,都属于React的合成事件,也就是非浏览器原生的,它是对浏览器原生事件的封装事件。react合成事件中,onChange事件类似于原生的input事件,只要按键就会触发,这在pc上面或者英文输入法中不会有任何问题,但是对于移动端输入时需要切换中文输入法或者其他不同输入法的其他语言的用户来说,会粗大事。比如上面这段最简单的代码,我们想要输入中文,比如"事件",我们需要在手机键盘按键'shijian',每按一次键都会触发onChange事件,然后会发现输入框的内容已经输入了英文字母,这不是我们需要的结果。那怎么解决呢?接下来,我们的主角出场--compositionEvent。组合事件可以帮助我们解决这个问题,可以参看组合事件参考文档

compositionEvent组合事件介绍

我们还是以输入中文为例,大家会发现,在移动设备中,中文的输入其实分为三个步骤(pc上其实也是一样),1:开始,2:敲键盘,3:点击选择中文。这个compositionEvent组合事件就是分拆了不同的步骤的事件的组合,这个组合事件是由compositionStart,compositionUpdate和compositionEnd三个事件的组合,Start和End事件只执行一次,Update会执行多次,只要没有选中中文之前,触发update事件,选中需要的选中的文字,就会触发end事件,一个组合事件完成,以此循环。了解了组合事件这个原理后,解决方案就不难理解了吧。

具体如何填坑

1、使用uncontrolled 组件的方式,抛弃onChange事件

使用这种方式就基本上与pc浏览器的效果就一致了,请看如下代码,只添加了组合事件中End的监听,意味着若我们完成输入最后一步选中操作后,才会触发该监听。大家肯定会疑问,这不就是的onInput效果吗,那不就能够支持到controlled组件的方式,对不起,真不行,因为输入确实完美契合,但是删除操作,就无法触发这个监听了。所以,如果不加上onChange事件的配合,那就使用uncontrolled组件的方式吧。

<input ref="inputTest" type="text" placeholder="测试" 
              onCompositionEnd={this.handleComposition} />

2、还是原来的controlled组件的配方,使用compositionEvent组合事件与onChange事件做兼容

上面已经提到controlled组件的解决方式了,那就是与onChange事件进行配合,那具体如何配合呢,请看代码如下:

<input ref="inputTest" type="text" placeholder="测试" 
              onCompositionStart={this.handlingComposition} 
              onCompositionUpdate={this.handlingComposition} 
              onCompositionEnd={this.handleComposition} 
              onChange={this.inputValue}/>
...
handlingComposition(){
    this.isCompositionEnd = false;
}
handleComposition(e){
    this.isCompositionEnd = true;
}
inputValue(e){
    if(this.isCompositionEnd){
        this.setState({
            val:e.target.value
        })
    }
}

以上代码会存在一点小问题,需要确保onCompositionEnd在onChange事件前触发,一旦有的浏览器存在兼容问题,两者的执行顺序相反,会导致onChange事件永不触发,因此,最好在handleComposition函数中重复执行一次onChange中的逻辑,避免出现兼容问题。 前端发展日新月异,交流也是很好的学习方式,有不对的地方,请喷!