一般來說,react上我們都會用change事件去處理input的輸入,但這樣就導致一個問題,在輸入中文的時候,我們還沒輸入完成就會觸發change事件,這樣顯然不是理想狀況。
那麼,怎麼解決這個問題呢?首先,你需要了解3個事件,compositionstart,compositionupdate和compositionend。什麼意思呢?
compositionstart
要開始輸入中文
compositionupdate
插入新字元
compositionend
輸入完成
下面是一段程式碼,可以copy感受一下
class App extends React.Component {
constructor(props) {
super(props)
}
compositionstart(event) {
console.log('開始輸入', event.data);
}
compositionupdate(event) {
document.getElementById('data').innerHTML = event.data;
console.log('正在輸入的資料', event.data);
}
compositionend(event) {
console.log('結束輸入', event.data);
}
changeEvent() {
console.log('改變');
}
render() {
return (
<div style={{padding:"50px"}}>
<input type="text" id="test" onChange={this.changeEvent.bind(this)}
onCompositionStart={this.compositionstart.bind(this)}
onCompositionUpdate={this.compositionupdate.bind(this)}
onCompositionEnd={this.compositionend.bind(this)}/>
<span style={{marginLeft:"50px"}}>輸入的資料為 <span id="data"></span></span>
</div>
)
}
}
window.onload = function () {
ReactDOM.render(
<App/>,
document.getElementById('root')
)
}
需要注意的是,要引入react和babel
然後,看一下效果
可以看到,我們再輸入中文的過程中,event.data為輸入的英文值,並且連英文字元之間的分隔符也有,這樣就導致一些問題,比如我們的input不允許輸入特殊字元,這樣我們如果用onchange去處理的話,顯然不行。所以我們要想辦法,在中文輸入完成之後,再處理onchange事件。
明白這幾個事件之後,怎麼辦呢?看這裡
var isOnComposition = true;
class App extends React.Component {
constructor(props) {
super(props)
}
handleComposition(e) {
console.log('type', e.type)
if (e.type === 'compositionend') {
// composition is end
isOnComposition = false
} else {
// in composition
isOnComposition = true
}
}
changeEvent() {
if (!isOnComposition) {
console.log('改變');
}
}
render() {
return (
<div>
<input type="text" id="test" onChange={this.changeEvent.bind(this)}
onCompositionStart={this.handleComposition.bind(this)}
onCompositionUpdate={this.handleComposition.bind(this)}
onCompositionEnd={this.handleComposition.bind(this)}/>
</div>
)
}
}
window.onload = function () {
ReactDOM.render(
<App/>,
document.getElementById('root')
)
}
這段程式碼,簡潔明瞭,我們定義一箇中間變數isOncomposition,預設為true,當觸發compositionend事件時,我們把它賦為false,這樣change事件就會執行。在除chrome之外的其他瀏覽器中,compositionend事件是先於change事件觸發的,所以上述程式碼可以很好的執行。
而在chrome瀏覽器中,change方法會先於compositionend事件執行,這樣的話,我們的change在執行時,isOncomposition永遠都是true。
怎麼辦呢?就是在compositionend中加一個判斷!isOnComposition && isChrome,當chrome瀏覽器時,會在compositionend結束,執行change的方法。
程式碼如下
var isOnComposition = false;
const isChrome = !!window.chrome && !!window.chrome.webstore
class App extends React.Component {
constructor(props) {
super(props)
}
handleComposition(e) {
console.log('type', e.type)
if (e.type === 'compositionend') {
// composition is end
isOnComposition = false
if (!isOnComposition && isChrome) {
// fire onChange
this.changeEvent(e);
}
} else {
// in composition
isOnComposition = true
}
}
changeEvent() {
if (!isOnComposition) {
console.log('改變');
}
}
render() {
return (
<div>
<input type="text" id="test" onChange={this.changeEvent.bind(this)}
onCompositionStart={this.handleComposition.bind(this)}
onCompositionUpdate={this.handleComposition.bind(this)}
onCompositionEnd={this.handleComposition.bind(this)}/>
</div>
)
}
}
window.onload = function () {
ReactDOM.render(
<App/>,
document.getElementById('root')
)
}
github地址如下,歡迎大家檢視