在不少项目中需要针对input的输入数据做相应的处理,比如讲用户数据的数据转换成对应的大写字母,那么问题就来了。当用户拿起手机,点中你的input组件后开始输入时,会发现IOS的手机在中文输入下会发生重复输入的情况。
举例来说,当用户在中文输入法下输入ABC这几个字母是,input的实际的value值(如果你把input的onChange事件打印出来或是设置成value的话),不是ABC而是AABABC,也就是说用户输入的会有缓存,而这在Android手机上没有出现。
那如何处理这个问题并使得针对IOS也能兼容呢?默认的流程都一样,预先google一下,会发现主流的方法是让我们监听compositionEvent,这是做什么的呢,可以从字面意思来理解,composition有组成和部分的意思,那么这个事件的触发其实就是用户切换了非英语的输入法模式后,数据由部分字母比如拼音组合而成时会触发的事件。
按照MDN上的简单介绍(确实够简单的了)和React官网的事件介绍,compositionEvent在react中共有三个具体的事件:onCompositionEnd onCompositionStart onCompositionUpdate。
接着在本地试了下,发现每次输入中文都会触发onCompositionStart和onCompositionUpdate,不过它们都没有传递相关的参数,所以说打印console.log(arguments)都是空的。
方案1:追加中文输入缓存的末尾字符
针对以上搜集及整理,针对input的兼容可以这样来实现:
class example extends React.Component{
constructor(props){
super(props);
this.state = {
value: ''
}
this.inputLock = false; // 标记是否处于composition的状态
}
// input事件调用
onChange(e){
let value = e.target.value;
if(this.inputLock){
// 处于中文输入状态,只添加最后一位字符
this.state.value += value.substr(value.length - 1).toUpperCase();
this.inputLock = false; // 由于每次输入中文字符都会触发onCompositionStart,所以在这里将其设置为false,以备下次触发
}else {
// 非中文输入,则正常操作,这里的需求是将字符转换成大写
this.state.value = value.toUpperCase();
}
}
render(){
return (
<input
value={
this.state.value}
onChange={
this.onChange.bind(this)}
onCompositionStart={()=>{
this.inputLock = true}}
/>
)
}
}
方案1中只用到了onCompositionStart,主要发现在IOS中无法触发onCompositionEnd事件(还没经过全面测试,了解的同学请赐教),虽然能够解决中午输入问题,但是存在一个很明显的bug,就是用