input输入中文时,如何过滤掉拼音

2,912 阅读2分钟

前言

🚀 对v-model这个功能实现原理已经很熟悉了,但是,今天发现input输入中文的时候,官网拼音被过滤掉了,对于这个功能之前没有特别注意,今天来想剖析一下它的实现。如果你对CompositionEvent比较陌生,那么请往下看..👀



说一说input事件带来的输入法问题

举出一个实际的应用情况,一个搜索计算机书籍的功能,用户可以在文本输入框里输入要搜索的书名,程序中是利用input事件触发,进行比对数据库中的书籍标题,当你想搜索一本名为"林哥的Java教程",第一个字为"林",拼音输入法需要输入"lin"三个键盘上的字符,在"林"这个字从输入法编辑器中加到真正的input元素前,input已经捕捉到"lin"三个字符,在列表中已搜索出一大堆有关"linux"的书籍。细节就不说了,还有可能对字符数量的的检查之类的问题。不过,这是正确的程序运作逻辑吗?很明显的这是一个大问题。 


键盘按键事件

keydown:按下一个键触发事件;
keypress:按下通常会产生字符值的键。此事件高度依赖设备,废弃;
keyup:释放一个键触发事件;
compositionstart:当用户使用拼音输入法开始输入汉字时,这个事件就会被触发;
compositionupdate:事件触发于字符被输入到一段文字的时候;
compositionend:当文本段落的组成完成或取消时, compositionend 事件将被触发;
input:元素的 value 被修改时,会触发 input 事件
change:当用户提交对元素值的更改时。与 input 事件不同,change 事件不一定会对元素值的每次更改触发。


看下键盘在输入中文时,触发事件的顺序,如下图:Google Chrome 版本 83.0.4103.106(正式版本) (64 位)


可见,在输入法输入中文时,input会被触发多次,而只触发了一次compositionEvent事件周期。


简单实现一个demo

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>CompositionEvent</title></head>
<body>
<p id="show"> </p>
<input id="input"type="text">
<script>
window.onload = function() {
      const inputEle = document.getElementById('input');
      const showEle = document.getElementById('show');
      inputEle.addEventListener('input', onInput);
      inputEle.addEventListener('compositionstart', onCompositionstart);
      inputEle.addEventListener('compositionend', onCompositionend);
      inputEle.addEventListener('change', onCompositionend);
      function onInput (e) {
        if(e.target.composing) {return}
        showValue(e.target.value);
      }
      function onCompositionstart (e) {
        e.target.composing = true;
      }
      function onCompositionend (e) {
        if(!e.target.composing) {return}
        e.target.composing = false;
        trigger(e.target, 'input');
      }
      function showValue(val){
        showEle.innerText = val;
      }
      function trigger (el, type) {
        const e = document.createEvent('HTMLEvents');
        e.initEvent(type, true, true);
        el.dispatchEvent(e);
      }
    }
  </script>
</body>
</html>

总结

总体来讲,compositionEvent 是一个很简单易懂的属性,但是web开发规避不了的bug是.. 兼容性!!以上只是对chrome的一个测试,ios10.3对 compositionEvent状态的触发顺序做了调整,变得跟chrome一样,所以在开发时要注意一下需要覆盖的设备做适当的调整。