...
<input ref="inputTest" type="text" placeholder="test" value={this.state.val}
onChange={this.inputValue}/>
...
inputValue(e){
this.setState({
val:e.target.value
})
}
以上這段代碼,相信大家再熟悉不過了,react 受控組件的最簡單的栗子,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中的邏輯,避免出現兼容問題。