zoukankan      html  css  js  c++  java
  • 检测 TextArea 的改动部分

    对于一个代码编辑器,例如 LaTeX 或者 Markdown 编辑器,如果想提供即时预览,就需要检测 TextArea 的改动部分。要是代码不长,在内容变动时逐字符比较 textarea 中的新旧内容即可。要是代码有几万个字符的长度,这样做效率就太低了。我们需要更方便的方法。

    前面已经说过,textarea 的当前光标选择范围是可以得知的。而 textarea 的内容变化,基本上是如下这些事件引起的:键盘事件(插入、删除),鼠标事件(选择、拖放),剪切板事件(剪切、粘贴)。在事件处理程序中,我们可以尝试用下面两种方法计算出 textarea 的改动部分:

    1. 从原来的光标选择范围以及所输入或粘贴的文本。
    2. 从原来的光标选择范围以及现在的光标选择范围。

    第一种方法需要处理各种情形,比较复杂。因此我们选择第二种方法。用这种方法,关键在于分清哪些情形应该处理,哪些情形应该忽略。

    为使光标范围的每次变化都可以捕捉到,至少需要监听如下这些事件:keydown,keyup,mousedown,mousemove,mouseup,cut,paste。其中使用 keydown 和 keyup 而不使用 keypress 是因为粘贴时不会触发该事件,而使用 mousedown 和 mousemove 是选择文本时会触发的事件。

    再看需要忽略部分。如下这些情形的光标范围变化只需记录下来,实际并没有内容变化:

    • textarea 无论是否在焦点的 mousedown 事件 
    • textarea 不在焦点时的 mousemove 事件
    • textarea 在焦点但是光标范围没变化时的 mousemove 事件

    用鼠标拖动选择文本的情形也需要处理好。这种情形和用鼠标选择文本的情形有些相似,它们同样是触发了 mousedown 和 mousemove 事件(后者最后还触发 mouseup 事件但前者没有)。但是前者有内容改动和后者没有改动。在大部分浏览器中,我们可以根据是否有选择文本来区分这两者。但 Firefox 有些特殊,拖动选择文本结束后会取消文本选择状态,将光标停留在选择文本的最后面。这样导致这两者有时无法区分,只能扩大范围进行字符比较。

    最复杂的问题是中文输入。中文输入开始时可以从 keydown 事件的 keycode = 229 或者 197 得知,但是结束时没法得知。另外,Chrome 会将输入法的候选文本也放在 textarea 中,而且输入时用鼠标点击候选词也可以完成输入。这种种问题导致要从各种事件中判断文本的修改非常困难。我们可以借鉴 CodeMirror 2 的处理方式:在开始输入文本时记录位置,在按控制键或者点击鼠标或者失去焦点时重置该位置。然后每次计算改动时都从该位置开始比较。

    参考资料:
    [1] JavaScript Madness: Keyboard Events
    [2] Javascript Madness: Mouse Events
    [3] oninput event | input event JavaScript
    [4] textInput event JavaScript
    [5] ime-mode - MDN
    [6] Detecting IME input before enter pressed in Javascript
    [7] how to detect multi-byte characters inputting end by javascript?
    [8] 在 JavaScript 中监听 IME 键盘输入事件 - Cat Chen
    [9] 中文输入法无法触发onkeyup事件的问题
    [A] DOM3 Events Keyflow from Olli Pettay on 2008-04-02
    [B] 从谷歌的一个Bug说起,谈谈键盘事件的兼容性
    [C] CodeMirror: Internals

  • 相关阅读:
    学习进度条73
    学习进度条72
    学习进度条71
    学习进度条70
    学习进度条69
    学习进度条68
    学习进度条67
    学习进度条66
    学习进度条65
    elasticsearch
  • 原文地址:https://www.cnblogs.com/zoho/p/2578885.html
Copyright © 2011-2022 走看看