react輸入框輸入中文bug


一般來說,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

<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

然后,看一下效果

可以看到,我們再輸入中文的過程中,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地址如下,歡迎大家查看

react-input


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM