需求:封装一个input输入组件
// Input 组件
const Input = () => {
const handleChange = (e: any) => {
console.log(inputValue)
}
return (
<input
type="text"
onChange={handleChange}
/>
)
}
export default Input
结果:问题不大,很快就撸出来了。但是使用中文输入法时,onChange事件会触发很多次,如下图:
出现这种结果的原因是拼音输入是一个过程,我们输入的每一个字母都触发了 onChange 事件。那如何处理才可以避免打印输入过程,只打印结果呢?
解决:使用 compositionEvent 事件
通过监听输入法开始输入到结束的事件,即监听 compositionstart 和 compositionend 方法,同时定义一个变量 isComposition,来判断是否处于中文输入过程当中,如果是,则不触发 onChange 后续操作。
let isComposition = false
const Input = () => {
const handleComposition = (e: any) => {
if (e.type === 'compositionend') {
isComposition = false
} else {
isComposition = true
}
}
const handleChange = (e: any) => {
if (!isComposition) {
const inputValue = e.target.value
console.log(inputValue)
}
}
return (
<input
type="text"
onCompositionStart={handleComposition}
onCompositionEnd={handleComposition}
onChange={handleChange}
/>
)
}
export default Input
你以为这样就结束了吗,并没有,在chrome浏览器输入中文没有打印结果。原因是chrome浏览器跟其他浏览器的执行顺序不同:
chrome浏览器:compositionstart -> onChange -> compositionend
非chrome浏览器:compositionstart -> compositionend -> onChange
下面针对chrome浏览器做一些特殊处理,如果是chrome浏览器,则在 compositionend 方法最后执行一次 onChange 方法,如下:
let isComposition = false
const isChrome = navigator.userAgent.indexOf('Chrome') > -1
const Input = () => {
const handleComposition = (e: any) => {
if (e.type === 'compositionend') {
isComposition = false
if (isChrome) {
handleChange(e)
}
} else {
isComposition = true
}
}
const handleChange = (e: any) => {
if (!isComposition) {
const inputValue = e.target.value
console.log(inputValue)
}
}
return (
<input
type="text"
onCompositionStart={handleComposition}
onCompositionEnd={handleComposition}
onChange={handleChange}
/>
)
}
export default Input
最后测试一下:
测试达到了预期效果,没有问题,愉快地去踩下一个坑了。