当前位置:   article > 正文

输入框事件compositionstart和compositionend的妙用

compositionstart

前段时间被这样一个bug给折磨到,在ios手机端,切换中文输入法输入打拼音到input输入框的时候,发现打拼音的时候也会频繁触发input事件以至于输入框一直处于抖动状态,加上防抖截流也无济于事反而会让用户觉得特别的卡顿。

问题排查:

1.公司项目用的是taro进行开发,所以是taro的问题吗?

查看了源码,发现taro只是做了一层套娃,底层是react框架

2.那react框架问题吗?

写了个react的demo发现,react其实也有这样的问题

  1. const Demo=()=>{
  2. const [value,setValue]=useState("");
  3. return (
  4. <>
  5. <input onInput={(e)=>{
  6. console.log("value:",e.target.value)
  7. setValue(e.target.value)
  8. }}/>
  9. <span>{value}</span>
  10. </>
  11. )
  12. }

 看过react的源码的人都会知道,react对于原生dom事件其实也是没有过多的去处理,于是我做了一下论证

3.是不是元素dom事件就是这样的呢?

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. <input type="text" >
  11. <script>
  12. const input=document.querySelector('input')
  13. input.addEventListener('input',function(e){
  14. console.log("e",e)
  15. })
  16. </script>
  17. </body>
  18. </html>

验证结果如下确实如此 

 那么接下来就轮到主角上场了

compositionstart

文本合成系统如 input method editor(即输入法编辑器)开始新的输入合成时会触发 compositionstart 事件。

例如,当用户使用拼音输入法开始输入汉字时,这个事件就会被触发。

compositionend

当文本段落的组成完成或取消时,compositionend 事件将被触发 (具有特殊字符的触发,需要一系列键和其他输入,如语音识别或移动中的字词建议)。

于是我对react代码的input输入框添加了以上两方法

  1. const Demo = () => {
  2. const [value, setValue] = useState("");
  3. return (
  4. <>
  5. <input
  6. onCompositionStart={(e) => {
  7. console.log("onCompositionStart")
  8. }}
  9. onInput={(e) => {
  10. console.log("value:", e.target.value);
  11. setValue(e.target.value);
  12. }}
  13. />
  14. <span>{value}</span>
  15. </>
  16. );
  17. };

当切换到中文输入到时候 compositionstart事件触发了

 当输入完成的时候compositionend触发了

当切换会英文输入的时候,就不会触发 

 于是乎对代码做了这样的改造:

  1. const Demo = () => {
  2. const [value, setValue] = useState("");
  3. return (
  4. <>
  5. <input
  6. onCompositionStart={(e) => {
  7. console.log("onCompositionStart")
  8. e.target.composing = true
  9. }}
  10. onCompositionEnd={(e) => {
  11. console.log("onCompositionEnd",e.target.value)
  12. if(!e.target.composing)return;
  13. (e.target.composing = false)
  14. setValue(e.target.value);
  15. }}
  16. onInput={(e) => {
  17. if(e.target.composing) return;
  18. console.log("value:", e.target.value);
  19. setValue(e.target.value);
  20. }}
  21. />
  22. <span>{value}</span>
  23. </>
  24. );
  25. };

 

 

也就完全解决了中文输入的时候输入框问题

以上解决思路其实来源于vue源码v-model的指令实现的时候对输入框事件做了的处理

  1. const directive = {
  2. inserted (el, binding, vnode, oldVnode) {
  3. if (vnode.tag === 'select') {
  4. // #6903
  5. if (oldVnode.elm && !oldVnode.elm._vOptions) {
  6. mergeVNodeHook(vnode, 'postpatch', () => {
  7. directive.componentUpdated(el, binding, vnode)
  8. })
  9. } else {
  10. setSelected(el, binding, vnode.context)
  11. }
  12. el._vOptions = [].map.call(el.options, getValue)
  13. } else if (vnode.tag === 'textarea' || isTextInputType(el.type)) {
  14. el._vModifiers = binding.modifiers
  15. if (!binding.modifiers.lazy) {
  16. el.addEventListener('compositionstart', onCompositionStart)
  17. el.addEventListener('compositionend', onCompositionEnd)
  18. // Safari < 10.2 & UIWebView doesn't fire compositionend when
  19. // switching focus before confirming composition choice
  20. // this also fixes the issue where some browsers e.g. iOS Chrome
  21. // fires "change" instead of "input" on autocomplete.
  22. el.addEventListener('change', onCompositionEnd)
  23. /* istanbul ignore if */
  24. if (isIE9) {
  25. el.vmodel = true
  26. }
  27. }
  28. }
  29. },
  1. function onCompositionStart (e) {
  2. e.target.composing = true
  3. }
  4. function onCompositionEnd (e) {
  5. // prevent triggering an input event for no reason
  6. if (!e.target.composing) return
  7. e.target.composing = false
  8. trigger(e.target, 'input')
  9. }
  10. function trigger (el, type) {
  11. const e = document.createEvent('HTMLEvents')
  12. e.initEvent(type, true, true)
  13. el.dispatchEvent(e)
  14. }

由此看出鱿大大,在写vue框架的时候是多么细心,这些细节都考虑到了

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/778003
推荐阅读
相关标签
  

闽ICP备14008679号