现象:
在将输入输入法切换到中文
的时候,在打拼音的过程中也会触发oninput事件,如下:
const Demo=()=>{
const [value,setValue]=useState("");
return (
<>
<input onInput={(e)=>{
console.log("value:",e.target.value)
setValue(e.target.value)
}}/>
<span>{value}</span>
</>
)
}
这样带来的一个问题就是在输入中文的过程中输入框可能会抖动,如何解这个问题呢?
input提供了compositionstart和compositionend两个事件,参考MDN链接。
解法:
对上述代码进行优化
const Demo = () => {
const [value, setValue] = useState("");
return (
<>
<input
onCompositionStart={(e) => {
console.log("onCompositionStart")
e.target.composing = true
}}
onCompositionEnd={(e) => {
console.log("onCompositionEnd",e.target.value)
if(!e.target.composing)return;
(e.target.composing = false)
setValue(e.target.value);
}}
onInput={(e) => {
if(e.target.composing) return;
console.log("value:", e.target.value);
setValue(e.target.value);
}}
/>
<span>{value}</span>
</>
);
};
这样就完全解决了中文输入的时候输入框问题。
以上解决思路其实来源于vue源码v-model的指令实现的时候对输入框事件做了的处理
const directive = {
inserted (el, binding, vnode, oldVnode) {
if (vnode.tag === 'select') {
// #6903
if (oldVnode.elm && !oldVnode.elm._vOptions) {
mergeVNodeHook(vnode, 'postpatch', () => {
directive.componentUpdated(el, binding, vnode)
})
} else {
setSelected(el, binding, vnode.context)
}
el._vOptions = [].map.call(el.options, getValue)
} else if (vnode.tag === 'textarea' || isTextInputType(el.type)) {
el._vModifiers = binding.modifiers
if (!binding.modifiers.lazy) {
el.addEventListener('compositionstart', onCompositionStart)
el.addEventListener('compositionend', onCompositionEnd)
// Safari < 10.2 & UIWebView doesn't fire compositionend when
// switching focus before confirming composition choice
// this also fixes the issue where some browsers e.g. iOS Chrome
// fires "change" instead of "input" on autocomplete.
el.addEventListener('change', onCompositionEnd)
/* istanbul ignore if */
if (isIE9) {
el.vmodel = true
}
}
}
},
function onCompositionStart (e) {
e.target.composing = true
}
function onCompositionEnd (e) {
// prevent triggering an input event for no reason
if (!e.target.composing) return
e.target.composing = false
trigger(e.target, 'input')
}
function trigger (el, type) {
const e = document.createEvent('HTMLEvents')
e.initEvent(type, true, true)
el.dispatchEvent(e)
}
由此看出鱿大大,在写vue框架的时候是多么细心,这些细节都考虑到了
参考链接:
输入框事件compositionstart和compositionend的妙用