The magical effect of input box input event compositionstart and compositionend

Phenomenon:

When entering the input method 切换到中文, the oninput event will also be triggered during the pinyin process, as follows:

const Demo=()=>{
    
    
  const [value,setValue]=useState("");
  return (
    <>
      <input onInput={
    
    (e)=>{
    
    
        console.log("value:",e.target.value)
        setValue(e.target.value)
      }}/>
      <span>{
    
    value}</span>
    </>
  )
}

insert image description here

One of the problems brought about by this is that the input box may shake during the process of inputting Chinese. How to solve this problem ?
input provides two events, compositionstart and compositionend, refer to the MDN link.

insert image description here

solution:

Optimize the above code

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>
    </>
  );
};

insert image description here
insert image description here
This completely solves the problem of the input box when inputting Chinese.


The above solutions actually come from the processing of input box events when the vue source code v-model instructions are implemented.

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)
}

From this we can see how careful squid was when writing the vue framework, and these details were taken into account

Reference link:
Magical use of input box events compositionstart and compositionend

Guess you like

Origin blog.csdn.net/yexudengzhidao/article/details/131555047